gbash

POSIX Shell

POSIX Shell Command Language compliance matrix for gbash.

Scope

This page tracks gbash conformance to the POSIX Shell Command Language as defined in XCU Chapter 2 of IEEE Std 1003.1-2024. It covers shell syntax, expansion, control flow, redirections, builtins, and variable semantics.

This is not a claim of formal POSIX certification. gbash targets practical compatibility with the shell command language for the features within its supported scope. Where POSIX and bash diverge, gbash generally follows bash unless its sandbox model requires otherwise.

What is in scope

  • Tokenization, quoting, and all expansion types
  • Field splitting and pathname expansion (globbing)
  • Redirections (file, heredoc, here-string, descriptor operations)
  • Simple commands, pipelines, lists, and compound commands
  • Shell functions and variable scoping
  • Special and regular builtins
  • Exit status semantics and errexit behavior
  • Trap handling for EXIT, ERR, DEBUG, and RETURN
  • Variable assignment, export, readonly, and environment passing
  • Shell options (set -e, set -u, set -o pipefail, etc.)

What is out of scope

  • Job control (bg, fg, jobs, suspend, process groups)
  • Real process model (fork, exec, wait on host PIDs)
  • TTY and terminal handling (stty, readline, interactive line editing)
  • Host signal delivery beyond pseudo-signals routed through the trap system
  • Host filesystem access (virtual filesystem by default)
  • Utilities outside the command registry (no PATH-based host binary search)

How conformance is measured

Each feature in the matrix below is classified as one of:

  • required -- POSIX mandates this behavior
  • unspecified -- POSIX leaves the behavior undefined; gbash documents its choice
  • implementation defined -- POSIX requires a behavior but lets the shell choose
  • extension -- bash extension beyond POSIX that gbash supports
  • out of scope -- POSIX requires it but gbash deliberately omits it

Status is determined by:

  1. Reviewing the existing OILS conformance test results and manifest
  2. Cross-referencing against the shell interpreter, expander, and builtin implementations
  3. Differential testing against a pinned version of bash

This matrix catalogs gbash conformance to the POSIX Shell Command Language. All feature descriptions are original summaries derived from reading the specification requirements.

Generated April 9, 2026 at 8:19 AM. Reference: IEEE Std 1003.1-2024, XCU Chapter 2.

In-Scope Pass Rate

93.23%

179 of 192 in-scope features

Partial

16

features with incomplete coverage

Out of Scope

9

features excluded by sandbox model

Total Features

201

across 15 categories

Coverage by Category

Expand categories to inspect individual features. Green indicates full conformance, amber indicates partial support, red indicates a failure, and gray indicates features outside scope.

Counts shown as pass / partial / fail.

Lexical Conventions and Tokenization12 / 0 / 0
12 features
FeatureTypeStatus
LEX-001Token boundary recognition at newlines and operators

The shell splits input into tokens at newline characters, operator characters, and whitespace boundaries following a defined precedence.

requiredpass
LEX-002Operator token recognition

Multi-character operators (&&, ||, <<, >>, etc.) are recognized as single tokens rather than sequences of single-character operators.

requiredpass
LEX-003Word formation from non-operator, non-delimiter characters

Contiguous characters that are not operators or unquoted whitespace form a single word token.

requiredpass
LEX-004Comment recognition with leading hash

A # character that is not quoted and appears where a new token could begin introduces a comment that extends to the next newline.

requiredpass
LEX-005Reserved word recognition in command position

Words like if, then, else, fi, do, done, case, esac, while, until, for, in, and function are recognized as reserved when they appear where a command name is expected.

requiredpass
LEX-006Reserved words not recognized mid-argument

A reserved word that appears as an argument to a command (not in command position) is treated as an ordinary word.

requiredpass
LEX-007Alias substitution before token recognition

When alias expansion is enabled, the shell replaces alias names with their definitions before further token processing.

Alias expansion is off by default in non-interactive mode per POSIX.

requiredpass
LEX-008Recursive alias expansion

If an alias definition ends with a blank, the next word after the alias is also checked for alias substitution. Self-referencing aliases must not loop infinitely.

Tricky edge case: alias a='b ' with alias b='a ' must terminate.

requiredpass
LEX-009IO_NUMBER token for redirection file descriptors

A sequence of digits immediately preceding a redirection operator (< or >) is recognized as a file descriptor number, not a word.

requiredpass
LEX-010Newline as command terminator and list separator

An unquoted newline terminates the current command, functioning equivalently to a semicolon in most contexts.

requiredpass
LEX-011Line continuation with backslash-newline

A backslash immediately followed by a newline is removed, joining the next line to the current one before tokenization.

requiredpass
LEX-012Here-document token recognition

The << and <<- operators are recognized as introducing here-documents. The delimiter word follows on the same line; the body extends to a line matching the delimiter exactly.

requiredpass
Quoting8 / 0 / 0
8 features
FeatureTypeStatus
QUOT-001Backslash escaping of single characters

A backslash preserves the literal value of the following character, except when followed by a newline (which triggers line continuation).

requiredpass
QUOT-002Single quotes preserve all characters literally

Characters enclosed in single quotes retain their literal meaning. No expansion or substitution occurs inside single quotes.

requiredpass
QUOT-003Double quotes allow parameter and command substitution

Double quotes preserve literal values except for $, `, \, and !. Parameter expansion, command substitution, and arithmetic expansion are performed inside double quotes.

requiredpass
QUOT-004Backslash inside double quotes

Inside double quotes, backslash retains its escaping meaning only before $, `, \, ", and newline. Before other characters the backslash is preserved literally.

requiredpass
QUOT-005Dollar-single-quote ANSI-C escaping

The $'...' form interprets backslash escape sequences (\\n, \\t, \\xHH, \\uHHHH, etc.) within single quotes, producing the corresponding byte values.

Added to POSIX in 2024 edition. Was previously a bash/ksh extension.

requiredpass
QUOT-006Dollar-double-quote locale translation

The $"..." form is intended for locale-dependent string translation. The shell may translate the enclosed string or treat it as a plain double-quoted string.

gbash treats $\"...\" identically to \"...\". Most shells do the same in practice.

implementation definedpass
QUOT-007Quote removal as final expansion step

After all expansions, unquoted quote characters (single, double, backslash) that were not produced by expansion are removed from the final word.

requiredpass
QUOT-008Quoting prevents reserved word recognition

Any form of quoting (backslash, single quotes, double quotes) on any character of a reserved word prevents it from being recognized as reserved.

requiredpass
Expansions32 / 0 / 0
32 features, 3 extensions
FeatureTypeStatus
EXP-001Tilde expansion to home directory

An unquoted tilde at the start of a word or after an unquoted colon in an assignment is replaced with the value of HOME (for bare ~) or the home directory of the named user (for ~user).

gbash uses sandbox user metadata; ~user resolves within the sandbox.

requiredpass
EXP-002Tilde expansion in assignments after colons

In variable assignments, tilde expansion also occurs after unquoted colons, enabling paths like PATH=~:~/bin to expand each tilde.

requiredpass
EXP-003Simple parameter expansion ($var and ${var})

A dollar sign followed by a name or braced name is replaced with the variable's value, or the empty string if unset (unless nounset is active).

requiredpass
EXP-004Positional parameters ($1 through $9 and ${N})

Shell parameters set from command-line arguments or function invocations are accessed as $1-$9 and ${10}, ${11}, etc.

requiredpass
EXP-005Special parameters ($@, $*, $#, $?, $$, $!, $0, $-)

The shell provides read-only special parameters for argument lists, argument count, last exit status, shell PID, last background PID, invocation name, and current option flags.

$$ and $! are virtual PIDs in gbash.

requiredpass
EXP-006"$@" preserves individual arguments in double quotes

When "$@" is expanded inside double quotes, each positional parameter becomes a separate field, preserving argument boundaries.

requiredpass
EXP-007"$*" joins arguments with first character of IFS

Inside double quotes, "$*" expands to a single field with all positional parameters joined by the first character of IFS.

requiredpass
EXP-008Default value expansion ${var:-word} and ${var-word}

Substitutes the expansion of word when var is unset (or unset/null with the colon form). The variable itself is not modified.

requiredpass
EXP-009Assign default ${var:=word} and ${var=word}

Like default value, but also assigns the expanded word to var when the substitution triggers.

requiredpass
EXP-010Error if unset ${var:?word} and ${var?word}

If var is unset (or unset/null with the colon form), the shell writes word to stderr and exits (in non-interactive shells).

requiredpass
EXP-011Alternate value ${var:+word} and ${var+word}

Substitutes the expansion of word when var IS set (and non-null with the colon form). Returns empty otherwise.

requiredpass
EXP-012String length ${#var}

Expands to the length in characters of the variable's value.

requiredpass
EXP-013Prefix removal ${var#pattern} and ${var##pattern}

Removes the shortest (# form) or longest (## form) prefix matching the pattern from the variable's value.

requiredpass
EXP-014Suffix removal ${var%pattern} and ${var%%pattern}

Removes the shortest (% form) or longest (%% form) suffix matching the pattern from the variable's value.

requiredpass
EXP-015Substring extraction ${var:offset:length}

Extracts a substring starting at the given offset for the given length. Negative offsets count from the end (requires a space or parentheses to disambiguate from default-value syntax).

Added in POSIX 2024. Negative offset edge cases differ across shells.

requiredpass
EXP-016Pattern substitution ${var/pattern/replacement}

Replaces the first match of pattern in the variable's value with the replacement string. The // form replaces all matches. The /# and /% forms anchor to the start or end respectively.

Added in POSIX 2024. Anchored forms are tested in OILS patsub tests.

requiredpass
EXP-017Case transformation ${var^}, ${var^^}, ${var,}, ${var,,}

Converts the first character (^ or ,) or all characters (^^ or ,,) of the variable's value to uppercase or lowercase respectively.

Added in POSIX 2024.

requiredpass
EXP-018Command substitution with $(command)

Executes command in a subshell and replaces the construct with the command's standard output, with trailing newlines removed.

requiredpass
EXP-019Command substitution with backticks

The older `command` form performs the same substitution as $(command) but has different quoting rules for nested backslashes and backticks.

Nested backtick quoting is a common edge-case source.

requiredpass
EXP-020Nested command substitution

The $(...) form can be nested to arbitrary depth. Each level starts a new parsing context.

requiredpass
EXP-021Arithmetic expansion $((expression))

The shell evaluates the arithmetic expression and replaces the construct with the decimal result. Standard integer operators (+, -, *, /, %, comparisons, bitwise, logical) are supported.

requiredpass
EXP-022Arithmetic variable references without $

Inside arithmetic expressions, variable names are recognized and expanded without requiring a $ prefix.

requiredpass
EXP-023Arithmetic assignment operators

Arithmetic expressions support = and compound assignment operators (+=, -=, *=, /=, %=, <<=, >>=, &=, ^=, |=).

requiredpass
EXP-024Arithmetic ternary operator

The expr ? expr : expr ternary conditional is supported in arithmetic expressions.

requiredpass
EXP-025Arithmetic comma operator

The comma operator evaluates both operands and returns the value of the right operand.

requiredpass
EXP-026Arithmetic pre/post increment and decrement

The ++var, var++, --var, and var-- operators modify a variable and return the value before or after modification.

Added in POSIX 2024.

requiredpass
EXP-027Arithmetic exponentiation operator

The ** operator raises the left operand to the power of the right.

Added in POSIX 2024. Right-associative.

requiredpass
EXP-028Expansion order (tilde, parameter, command, arith, field split, pathname, quote removal)

Expansions are performed in a defined sequence. Tilde expansion first, then parameter/command/arithmetic in a single pass left-to-right, then field splitting, then pathname expansion, then quote removal.

The ordering is a frequent source of subtle bugs across shells.

requiredpass
EXP-029Brace expansion {a,b,c} and {1..10}

Brace expansion generates multiple words from comma-separated alternatives or numeric/alphabetic sequences. Not part of POSIX; originated in csh/bash.

Bash extension. Controlled by set -B / set +B.

extensionpass
EXP-030Process substitution <(cmd) and >(cmd)

Process substitution connects a command's output or input to a file-like path that other commands can read from or write to.

Bash/ksh extension. gbash implements this with sandbox-owned pipes.

extensionpass
EXP-031Indirect expansion ${!var}

Expands to the value of the variable whose name is stored in var.

Bash extension. POSIX uses namerefs instead.

extensionpass
EXP-032Expansion of $LINENO

$LINENO expands to the current line number within the script or function being executed.

requiredpass
Field Splitting7 / 0 / 0
7 features
FeatureTypeStatus
FSPLIT-001Field splitting on IFS whitespace characters

After expansion, unquoted results of parameter expansion, command substitution, and arithmetic expansion are split into fields at sequences of IFS whitespace characters (space, tab, newline by default).

requiredpass
FSPLIT-002IFS non-whitespace characters as field delimiters

Non-whitespace characters in IFS act as explicit delimiters. Each occurrence produces a field boundary. Adjacent IFS non-whitespace characters produce empty fields between them.

Common pitfall: IFS=: with value 'a::b' must produce three fields.

requiredpass
FSPLIT-003Empty IFS disables field splitting

When IFS is set to the empty string, no field splitting occurs. The entire expansion result becomes a single field.

requiredpass
FSPLIT-004Unset IFS behaves as default (space/tab/newline)

When IFS is unset, field splitting behaves as if IFS were set to space, tab, and newline.

requiredpass
FSPLIT-005Leading and trailing IFS whitespace trimming

Sequences of IFS whitespace at the beginning or end of an expansion result do not produce empty leading or trailing fields.

requiredpass
FSPLIT-006Field splitting suppressed inside double quotes

Expansions occurring within double quotes are not subject to field splitting (except "$@" which splits on argument boundaries).

requiredpass
FSPLIT-007IFS with mixed whitespace and non-whitespace

When IFS contains both whitespace and non-whitespace characters, IFS whitespace is trimmed around non-whitespace delimiters, and the non-whitespace character alone acts as the delimiter.

Subtle interaction. IFS=' :' with ' a : b ' should produce [a, b].

requiredpass
Pathname Expansion9 / 1 / 0
10 features, 2 extensions
FeatureTypeStatus
PNAME-001Asterisk * matches any string

An unquoted * in a word matches any string of zero or more characters in filenames.

requiredpass
PNAME-002Question mark ? matches single character

An unquoted ? matches exactly one character in filenames.

requiredpass
PNAME-003Bracket expression [abc] character class matching

Bracket expressions match a single character from a set or range. Supports character ranges [a-z], negation [!abc] or [^abc], and named classes like [:alpha:].

requiredpass
PNAME-004Dot files excluded from * and ? by default

Filenames beginning with a period are not matched by * or ? unless the pattern also begins with a literal period.

dotglob shopt overrides this behavior (bash extension).

requiredpass
PNAME-005Slash characters never matched by wildcards

A slash in a pathname can only be matched by a literal slash in the pattern, never by *, ?, or bracket expressions.

requiredpass
PNAME-006Pattern that matches no files expands to itself

When a glob pattern matches no files, the pattern word is left unchanged (unless nullglob or failglob are enabled).

nullglob and failglob are bash extensions.

requiredpass
PNAME-007Pathname expansion disabled by set -f (noglob)

When the noglob option is set, pathname expansion is not performed and glob characters are treated as literal.

requiredpass
PNAME-008Glob results sorted in collation order

Pathnames generated by globbing are sorted according to the current locale's collation sequence.

gbash uses deterministic UTF-8 sorting which may differ from locale-based collation in some edge cases.

requiredpartial
PNAME-009Extended glob patterns ?(pat), *(pat), +(pat), @(pat), !(pat)

When extglob is enabled, extended pattern matching operators allow matching zero-or-one, zero-or-more, one-or-more, exactly-one, or none of the given patterns.

Bash/ksh extension enabled by shopt -s extglob.

extensionpass
PNAME-010Recursive glob with ** (globstar)

When globstar is enabled, ** in a pathname matches zero or more directories recursively.

Bash extension enabled by shopt -s globstar.

extensionpass
Redirection14 / 0 / 0
14 features, 2 extensions
FeatureTypeStatus
REDIR-001Input redirection with < file

Opens the named file for reading on stdin (fd 0) or the specified file descriptor.

requiredpass
REDIR-002Output redirection with > file

Opens the named file for writing on stdout (fd 1) or the specified file descriptor. Creates the file if it does not exist; truncates it if it does.

requiredpass
REDIR-003Append redirection with >> file

Opens the named file for appending on stdout or the specified file descriptor. Creates the file if it does not exist.

requiredpass
REDIR-004Noclobber protection with set -C and >|

When the noclobber option is set, > fails if the target file exists and is a regular file. The >| operator overrides this protection.

requiredpass
REDIR-005Here-document << delimiter

Reads input until a line containing only the delimiter is found. If the delimiter is unquoted, parameter expansion, command substitution, and arithmetic expansion occur in the body.

requiredpass
REDIR-006Here-document with quoted delimiter (no expansion)

When any part of the delimiter word is quoted, no expansion is performed in the here-document body.

requiredpass
REDIR-007Here-document tab stripping with <<-

The <<- form strips leading tab characters from each line of the here-document body and from the closing delimiter line.

requiredpass
REDIR-008Here-string <<< word

Provides the expansion of word as stdin to a command, with a trailing newline appended.

Bash/ksh/zsh extension, not in POSIX.

extensionpass
REDIR-009Descriptor duplication with n>&m and n<&m

Duplicates file descriptor m onto descriptor n. The >&m form is for output descriptors; <&m is for input descriptors.

requiredpass
REDIR-010Descriptor closing with n>&- and n<&-

Closes file descriptor n.

requiredpass
REDIR-011Read-write redirection with <> file

Opens the named file for both reading and writing on the specified descriptor (default fd 0).

requiredpass
REDIR-012Multiple redirections on a single command

A command may have multiple redirections which are applied left-to-right before the command executes.

requiredpass
REDIR-013Redirection applied to compound commands

Redirections may be placed after compound commands (if, while, for, case, brace groups, subshells) and apply to all commands within the construct.

requiredpass
REDIR-014Named file descriptor allocation with {varname}> and {varname}<

The shell allocates a file descriptor >= 10 and assigns the number to the named variable.

Bash 4.1+ extension.

extensionpass
Simple Commands5 / 2 / 0
8 features
FeatureTypeStatus
SCMD-001Simple command execution with argument list

A simple command is a sequence of variable assignments and redirections, optionally followed by a command name and arguments. The command name is looked up and executed.

requiredpass
SCMD-002Variable assignments as prefix to a command

Variable assignments preceding a command name are placed in the environment of that command only (temporary bindings). If the command is a special builtin, the assignments persist.

temp-binding behavior has known xfails for edge cases.

requiredpass
SCMD-003Variable assignment without a command name

When a simple command has assignments but no command name, the assignments take effect in the current shell environment.

requiredpass
SCMD-004Command search order (special builtins, functions, builtins, PATH)

The shell searches for commands in order: special builtins, shell functions, regular builtins, then external commands via PATH.

gbash has no PATH-based external command search; all commands are registry-backed.

requiredpartial
SCMD-005Command not found exits with status 127

If a command cannot be found, the exit status is 127.

requiredpass
SCMD-006Command found but not executable exits with status 126

If a command is found but cannot be executed (e.g., missing execute permission), the exit status is 126.

Not applicable to gbash's registry model; all registered commands are executable.

requirednot applicable
SCMD-007Empty command (only redirections or assignments)

A command consisting only of redirections applies them in the current environment. A command of only assignments sets variables in the current environment.

requiredpass
SCMD-008exec builtin replaces shell or applies redirections

The exec builtin with a command argument replaces the shell process. Without a command argument, redirections are applied to the current shell.

exec with a command does not replace the process in gbash (no real exec). exec with redirections works.

requiredpartial
Pipelines and Lists9 / 1 / 0
10 features, 1 extensions
FeatureTypeStatus
PIPE-001Pipeline connects stdout of left command to stdin of right

The | operator creates a pipeline where the standard output of the command on the left is connected to the standard input of the command on the right.

requiredpass
PIPE-002Pipeline exit status is the last command's exit status

The exit status of a pipeline is the exit status of the last command in the pipeline.

requiredpass
PIPE-003Pipeline negation with ! prefix

Prefixing a pipeline with ! inverts its exit status: zero becomes one, and non-zero becomes zero.

requiredpass
PIPE-004Pipefail option (set -o pipefail)

When pipefail is set, the pipeline exit status is the rightmost command that exited with non-zero status, or zero if all succeeded.

Added to POSIX in 2024. Was previously a bash extension.

requiredpass
PIPE-005PIPESTATUS array captures per-stage exit codes

The PIPESTATUS array variable contains the exit status of each command in the most recent pipeline.

Bash extension.

extensionpass
PIPE-006Sequential list with semicolon (cmd1 ; cmd2)

Commands separated by ; are executed sequentially. The shell waits for each command to complete before starting the next.

requiredpass
PIPE-007AND list (cmd1 && cmd2)

The right command executes only if the left command exits with status zero.

requiredpass
PIPE-008OR list (cmd1 || cmd2)

The right command executes only if the left command exits with non-zero status.

requiredpass
PIPE-009Asynchronous list with & (background execution)

A command terminated by & is executed asynchronously. The shell does not wait for it to complete and sets $! to its process ID.

gbash supports basic background execution but with virtual PIDs and no job control.

requiredpartial
PIPE-010Pipeline components execute in subshell environment

Each command in a pipeline may execute in a subshell. Variable assignments in pipeline stages do not affect the parent shell (unless lastpipe is enabled for the final stage).

lastpipe support is a bash extension that gbash implements.

requiredpass
Compound Commands14 / 1 / 0
15 features, 4 extensions
FeatureTypeStatus
COMP-001if/then/elif/else/fi conditional

Executes the then-body if the condition command list exits with status zero. Supports elif chains and a final else clause.

requiredpass
COMP-002while loop (while/do/done)

Repeatedly executes the body while the condition command list exits with status zero.

requiredpass
COMP-003until loop (until/do/done)

Repeatedly executes the body until the condition command list exits with status zero (opposite of while).

requiredpass
COMP-004for loop iterating over word list

The for var in word... form iterates over the expanded word list, assigning each word to the variable and executing the body.

requiredpass
COMP-005for loop without word list (iterates over positional parameters)

The for var (without in) iterates over the positional parameters, equivalent to for var in \"$@\".

requiredpass
COMP-006C-style for loop for (( init; cond; step ))

Arithmetic for loop that evaluates init once, tests cond before each iteration, and evaluates step after each iteration.

Bash/ksh extension.

extensionpass
COMP-007case/esac pattern matching

Matches a word against patterns and executes the corresponding command list for the first matching pattern. Patterns support shell wildcards. Multiple patterns per clause are separated by |.

requiredpass
COMP-008case fall-through with ;& and ;;&

The ;& terminator falls through to the next clause's commands unconditionally. The ;;& terminator continues testing subsequent patterns.

Added to POSIX in 2024. Previously a bash extension.

requiredpass
COMP-009Brace group { list; }

Groups commands for execution in the current shell environment. Unlike a subshell, variable assignments and redirections persist.

requiredpass
COMP-010Subshell ( list )

Executes the command list in a subshell environment. Variable changes, directory changes, and other state modifications do not affect the parent shell.

gbash simulates subshells with state cloning, not fork.

requiredpass
COMP-011Arithmetic command (( expression ))

Evaluates an arithmetic expression. Returns exit status 0 if the result is non-zero, and status 1 if the result is zero.

Bash/ksh extension.

extensionpass
COMP-012Conditional expression [[ expression ]]

Extended test command with pattern matching (==), regex matching (=~), and logical operators (&&, ||, !) without the quoting pitfalls of the [ command.

Bash/ksh extension. Not in POSIX (which uses test/[ only).

extensionpass
COMP-013select loop for menu generation

Displays a numbered menu from a word list, reads the user's choice, and assigns the selected word to a variable.

Bash/ksh extension. Limited utility in sandbox/non-interactive mode.

extensionpass
COMP-014break and continue in loops

break exits the innermost (or Nth) enclosing loop. continue skips to the next iteration of the innermost (or Nth) enclosing loop.

break/continue in loop conditions has a known xfail.

requiredpass
COMP-015Empty compound command bodies

Whether empty bodies in if/then/fi or while/do/done are accepted or rejected is not specified by POSIX. Bash accepts them.

gbash has xfails for empty then/fi and empty do/done cases.

unspecifiedpartial
Shell Functions7 / 1 / 0
8 features, 2 extensions
FeatureTypeStatus
FUNC-001Function definition with name() compound-command

Defines a shell function that can be invoked as a simple command. The body is any compound command (typically a brace group).

requiredpass
FUNC-002Function definition with function keyword

The function name { ... } syntax is an alternative way to define functions.

Bash/ksh extension.

extensionpass
FUNC-003Functions receive positional parameters from caller

When a function is invoked, the arguments become the function's positional parameters. The caller's positional parameters are saved and restored when the function returns.

requiredpass
FUNC-004return builtin exits function with specified status

The return builtin causes the function to exit with the given status (or the status of the last command if no argument).

requiredpass
FUNC-005Local variables with local/declare in functions

The local builtin creates function-scoped variables that are destroyed when the function returns. POSIX does not require local variables but most shells support them.

local is a bash extension. POSIX added it in 2024 as an XSI extension.

extensionpass
FUNC-006Functions share the shell's execution environment

Functions execute in the current shell environment (not a subshell). Variable assignments in a function are visible to the caller unless the variable is declared local.

requiredpass
FUNC-007Recursive function calls

Functions can call themselves recursively. Each invocation gets its own positional parameters.

requiredpass
FUNC-008Function names with special characters

POSIX requires function names to be valid shell names. Whether names containing $, -, or other non-name characters are accepted is unspecified.

Known xfails for function names with $ and command sub.

unspecifiedpartial
Builtins25 / 5 / 0
30 features, 4 extensions
FeatureTypeStatus
BTIN-001Special builtins persist variable assignments

Variable assignments preceding special builtins (break, :, ., continue, eval, exec, exit, export, readonly, return, set, shift, times, trap, unset) persist in the shell environment after the builtin completes.

requiredpass
BTIN-002Special builtin errors may cause non-interactive shell to exit

Certain errors in special builtins (like a redirection error) may cause a non-interactive shell to exit, unlike regular builtins.

gbash may not exit on all POSIX-required special-builtin errors.

requiredpartial
BTIN-003colon (:) null command

The : command does nothing and exits with status 0. Used for side effects of expansions in its arguments.

requiredpass
BTIN-004dot (.) source a script file

Reads and executes commands from a file in the current shell environment. The file is searched for in PATH if not found by pathname.

requiredpass
BTIN-005eval concatenates and executes arguments

Concatenates all arguments with spaces and executes the result as a shell command in the current environment.

requiredpass
BTIN-006export marks variables for child environments

Marks named variables to be included in the environment of subsequently executed commands.

requiredpass
BTIN-007readonly prevents variable modification

Marks named variables as readonly. Subsequent attempts to assign or unset them produce an error.

Some readonly assignment edge cases have known xfails.

requiredpass
BTIN-008set modifies shell options and positional parameters

With option flags, enables or disables shell behaviors. With arguments after --, replaces positional parameters. Without arguments, lists all shell variables.

requiredpass
BTIN-009shift removes leading positional parameters

Shifts positional parameters by the specified count (default 1). $1 becomes the value of $(1+n), and $# decreases by n.

requiredpass
BTIN-010times displays accumulated process times

Prints accumulated user and system CPU times for the shell and its children.

gbash reports synthetic times. Known xfail for format differences.

requiredpartial
BTIN-011trap sets signal and event handlers

Associates a command string with a signal or pseudo-signal. When the signal arrives, the command is executed. Supports EXIT, ERR, DEBUG, and RETURN traps.

requiredpass
BTIN-012unset removes variables or functions

Removes the named variable from the shell environment. With -f, removes the named function.

Dynamic scoping with unset has known edge-case xfails.

requiredpass
BTIN-013exit terminates the shell

Exits the shell with the given status (or the status of the last command executed). EXIT traps are executed before termination.

requiredpass
BTIN-014test / [ conditional expression evaluation

Evaluates a conditional expression and returns 0 (true) or 1 (false). Supports file tests, string tests, integer comparisons, and logical operators.

requiredpass
BTIN-015echo outputs arguments

Writes its arguments separated by spaces to stdout, followed by a newline.

echo -n and -e behavior is implementation-defined in POSIX. gbash follows bash.

requiredpass
BTIN-016printf formatted output

Formats and prints arguments according to a format string, similar to C printf. Supports %s, %d, %o, %x, %f, %e, %g, %b, %q, etc.

requiredpass
BTIN-017read reads a line from stdin

Reads a line from standard input and splits it according to IFS into the named variables. The last variable receives the remainder.

requiredpass
BTIN-018cd changes working directory

Changes the current working directory. Supports -, CDPATH search, and -P (physical) vs -L (logical) path handling.

requiredpass
BTIN-019pwd prints working directory

Prints the absolute pathname of the current working directory. Supports -P (physical, no symlinks) and -L (logical, default).

requiredpass
BTIN-020type describes command type

Indicates how each argument would be interpreted as a command name (alias, function, builtin, file, or keyword).

type -P and type -a have known xfails on Darwin.

requiredpass
BTIN-021command bypasses functions

Executes a command bypassing shell function lookup. With -v, describes the command. With -p, searches only the default PATH.

command -p has a known xfail (default PATH differs in sandbox).

requiredpartial
BTIN-022getopts parses positional parameters

Parses option flags from positional parameters according to an option string. Sets OPTARG and OPTIND.

requiredpass
BTIN-023umask sets file creation mask

Gets or sets the file mode creation mask. Supports both symbolic and octal notation.

requiredpass
BTIN-024wait waits for background processes

Waits for the specified process or job to complete and returns its exit status. Without arguments, waits for all background children.

gbash wait works for virtual background jobs only.

requiredpartial
BTIN-025kill sends signals to processes

Sends a signal (default SIGTERM) to the specified process IDs or job specifications.

gbash kill only operates on virtual PIDs within the shell family.

requiredpartial
BTIN-026hash remembers command locations

Remembers the locations of commands found via PATH search. With -r, clears the remembered locations.

In gbash, all commands are registry-backed so hashing is a no-op concept.

requiredpass
BTIN-027declare/typeset sets variable attributes

Sets variable attributes such as integer (-i), readonly (-r), export (-x), lowercase (-l), uppercase (-u), array (-a), associative (-A), and nameref (-n).

Bash extension. Core to bash scripting patterns.

extensionpass
BTIN-028mapfile/readarray reads lines into array

Reads lines from stdin into an indexed array variable.

Bash extension.

extensionpass
BTIN-029let evaluates arithmetic expressions

Evaluates each argument as an arithmetic expression.

Bash extension.

extensionpass
BTIN-030enable enables or disables builtins

Enables or disables shell builtin commands by name.

Bash extension.

extensionpass
Shell Invocation and Options9 / 0 / 0
10 features
FeatureTypeStatus
INVOC-001Shell reads commands from -c string argument

When invoked with -c, the shell reads commands from the provided string operand rather than from a file or stdin.

requiredpass
INVOC-002Shell reads commands from a script file

When invoked with a filename argument, the shell reads and executes commands from that file.

requiredpass
INVOC-003Shell reads from stdin when no file or -c

In interactive mode, the shell reads commands from standard input when no script file or -c string is provided.

gbash is non-interactive by design; stdin reading is through the API.

requirednot applicable
INVOC-004errexit option (set -e)

When set, the shell exits immediately if a simple command fails, unless the command is part of a condition (if, while, until, && / || chain, or negated with !).

Numerous edge cases. Existing OILS tests cover many of them.

requiredpass
INVOC-005nounset option (set -u)

When set, expanding an unset variable (other than $@ and $*) produces an error and causes the shell to exit.

requiredpass
INVOC-006verbose option (set -v)

When set, the shell writes each input line to stderr before executing it.

requiredpass
INVOC-007xtrace option (set -x)

When set, the shell writes each command to stderr (prefixed by the expansion of PS4) before execution.

Known xfail for escape style of unprintable characters.

requiredpass
INVOC-008noexec option (set -n)

When set, the shell reads commands but does not execute them. Used for syntax checking.

requiredpass
INVOC-009allexport option (set -a)

When set, all variable assignments are automatically exported.

requiredpass
INVOC-010noclobber option (set -C)

When set, output redirection with > fails if the file already exists and is a regular file.

requiredpass
Exit Status and Error Handling7 / 1 / 0
9 features, 1 extensions
FeatureTypeStatus
EXIT-001Exit status 0 indicates success

An exit status of zero indicates the command completed successfully.

requiredpass
EXIT-002Exit status 1-125 indicate command-specific failures

Non-zero exit statuses from 1 to 125 indicate various command-defined error conditions.

requiredpass
EXIT-003Exit status 126 for permission denied

A command found but not executable (permission denied) should produce exit status 126.

Not applicable to gbash registry model.

requirednot applicable
EXIT-004Exit status 127 for command not found

A command that cannot be found produces exit status 127.

requiredpass
EXIT-005Exit status > 128 for signal termination

When a command is terminated by a signal, the exit status is 128 plus the signal number.

gbash implements this for trapped signals on virtual PIDs.

requiredpartial
EXIT-006errexit interactions with compound commands

In the context of errexit, failures in conditions of if/while/until, in commands negated with !, and in the left side of && or || do not trigger an immediate exit.

Complex area. Tested extensively in OILS errexit tests.

requiredpass
EXIT-007$? reflects last command's exit status

The $? special parameter always holds the exit status of the most recently completed foreground command or pipeline.

requiredpass
EXIT-008errtrace option (set -E) for ERR trap inheritance

When set, shell functions, command substitutions, and subshell environments inherit the ERR trap from the parent.

Bash extension.

extensionpass
EXIT-009Syntax errors cause non-interactive shell to exit

A syntax error in a non-interactive shell causes it to exit with a non-zero status.

requiredpass
Traps, Signals, and Job Control8 / 2 / 0
13 features, 3 extensions, 3 out of scope
FeatureTypeStatus
TRAP-001EXIT trap fires on shell exit

A trap registered for EXIT is executed when the shell terminates, whether by reaching the end of input, executing exit, or receiving a fatal signal.

requiredpass
TRAP-002Signal traps (SIGINT, SIGTERM, etc.)

The shell can register handlers for standard signals. When the signal is received, the handler command is executed.

gbash routes signals through a virtual mechanism; not all signals are deliverable.

requiredpartial
TRAP-003trap with no arguments lists active traps

Invoking trap without arguments outputs the currently set traps in a form suitable for re-evaluation.

requiredpass
TRAP-004trap '' SIGNAL ignores the signal

Setting a trap action to the empty string causes the signal to be ignored.

requiredpass
TRAP-005trap - SIGNAL resets to default

Setting a trap action to - resets the signal disposition to the default.

requiredpass
TRAP-006Traps inherited across subshells

When a subshell is created, traps that were set to be ignored are inherited. Traps set to a command string are reset to default in the subshell.

requiredpass
TRAP-007ERR trap fires on command failure

The ERR trap fires after any simple command exits with non-zero status, subject to errexit-like exemptions.

Bash extension.

extensionpass
TRAP-008DEBUG trap fires before each command

The DEBUG trap fires before each simple command, for command, case command, and select command.

Bash extension.

extensionpass
TRAP-009RETURN trap fires on function/source return

The RETURN trap fires each time a function or sourced script returns.

Bash extension.

extensionpass
TRAP-010Job control with bg, fg, jobs

POSIX job control allows suspending, resuming, and switching between foreground and background jobs using bg, fg, and jobs.

gbash does not implement job control. No process suspension or TTY.

out of scopenot applicable
TRAP-011Job control monitor mode (set -m)

When monitor mode is enabled, the shell places each pipeline in its own process group and reports job completions.

gbash does not implement process groups or job monitoring.

out of scopenot applicable
TRAP-012Job specifications (%1, %%, %string)

POSIX defines job specifications for referring to background jobs by number, by current/previous status, or by command prefix.

gbash does not implement job specifications.

out of scopenot applicable
TRAP-013SIGPIPE handling in pipelines

When a pipeline reader exits, writers should receive SIGPIPE and terminate rather than blocking or accumulating output.

Known xfail for SIGPIPE regression test.

requiredpartial
Environment and Variable Assignment13 / 2 / 0
15 features, 6 extensions
FeatureTypeStatus
ENV-001Variable assignment with simple name=value syntax

Variables are assigned using name=value syntax. The value undergoes tilde expansion, parameter expansion, command substitution, arithmetic expansion, and quote removal.

requiredpass
ENV-002Append assignment with +=

The += operator appends to an existing variable's value (or adds to an array).

Bash extension.

extensionpass
ENV-003Exported variables passed to child commands

Variables marked with export are included in the environment of all subsequently executed commands.

requiredpass
ENV-004Subshell inherits full variable environment

A subshell receives a copy of the parent's variables, functions, traps, and other state. Modifications in the subshell do not affect the parent.

requiredpass
ENV-005Temporary variable assignments for simple commands

Variable assignments before a command name are placed in the environment of that command only and do not persist (unless the command is a special builtin).

Edge cases around temp bindings have known xfails in OILS tests.

requiredpass
ENV-006IFS variable controls field splitting

The IFS variable determines the characters used for field splitting after expansion and by the read builtin.

requiredpass
ENV-007PATH variable controls command search

The PATH variable contains a colon-separated list of directories to search for external commands.

gbash does not search PATH for host binaries. PATH is used for . (source) file lookup.

requiredpartial
ENV-008HOME variable used for tilde expansion

The HOME variable's value is substituted for ~ in tilde expansion.

requiredpass
ENV-009PWD and OLDPWD track working directory

PWD holds the current working directory pathname. OLDPWD holds the previous working directory (set by cd).

requiredpass
ENV-010Indexed arrays

Bash-style indexed arrays with arr[i]=val syntax, ${arr[@]}, ${arr[*]}, ${#arr[@]}, and ${!arr[@]}.

Bash extension. Core to many bash scripts.

extensionpass
ENV-011Associative arrays

Associative arrays declared with declare -A, supporting arbitrary string keys.

Bash extension.

extensionpass
ENV-012Name references (declare -n)

A nameref variable acts as an alias for another variable. Reading or assigning the nameref operates on the referenced variable.

Bash 4.3+ extension.

extensionpass
ENV-013RANDOM variable produces pseudo-random integers

Each expansion of $RANDOM yields a pseudo-random integer between 0 and 32767. Assigning to RANDOM seeds the generator.

Bash extension. gbash's RANDOM is seedable for deterministic replay.

extensionpass
ENV-014SECONDS tracks elapsed time

SECONDS expands to the number of seconds since the shell started (or since last assigned).

Bash extension.

extensionpass
ENV-015Dynamic scoping for shell variables

Shell variables use dynamic scoping in functions. A function sees the caller's variables unless local is used. Unset in dynamic scope reveals the previous scope's value.

Multiple known xfails for dynamic-unset and tempenv interactions.

requiredpartial

Deliberate Deviations

gbash is a sandbox-only runtime. Several POSIX requirements are fundamentally incompatible with this model. The table below catalogs every known deviation with rationale.

Sandbox-imposed limitations

No real process model -- POSIX assumes fork/exec semantics. gbash uses Go goroutines and a command registry. Subshells are simulated via state cloning. $$, $BASHPID, and $PPID are virtual. exec with a command does not replace the process; exec with only redirections works normally.

No host filesystem -- gbash defaults to an in-memory virtual filesystem. Device files are limited to /dev/null, /dev/zero, /dev/stdin, /dev/stdout, /dev/stderr. No /proc or /sys. Symlink traversal is denied by default.

No job control -- bg, fg, jobs, disown, suspend are not available. set -m has no effect. Job specifications (%1, %%) are not supported. Background & works with virtual job IDs but jobs cannot be suspended or resumed.

No real signal delivery -- kill only sends to virtual PIDs within the shell family. Signal masking is not implemented. SIGPIPE behavior in pipelines may differ.

No TTY -- No stty, terminal capabilities, readline, or SIGWINCH. test -t returns false for sandbox descriptors.

Intentional behavioral divergences

Determinism over compatibility -- Glob results use deterministic UTF-8 sorting (may differ from locale collation). $RANDOM is seedable. Process IDs are stable and predictable.

Command-not-found -- gbash returns exit 127 for any command not in the registry. No host binary fallthrough.

Sandbox metadata -- uname, hostname, whoami, id return sandbox values. Environment inheritance is controlled. Output size, loop iterations, and substitution depth are bounded by policy.

Error messages -- Arithmetic errors, xtrace escaping, parse errors, and coreutils error messages may differ from bash's exact format.

Variable scoping -- Dynamic scoping with unset in nested functions, temporary bindings before builtins, and FUNCNAME substring operators have minor behavioral differences.

Deviation table

IDPOSIX Requirementgbash BehaviorRationale
SCMD-004Search PATH for external commandsRegistry lookup onlySandbox: no host fallthrough
SCMD-006Exit 126 for permission deniedNot applicableAll registered commands are executable
SCMD-008exec replaces the shellRedirections onlyNo real process replacement
PIPE-009Background & with real PIDsVirtual job IDsNo fork/exec model
PNAME-008Glob sorted by locale collationDeterministic UTF-8 sortDeterminism over locale
COMP-015Empty compound bodiesPartially acceptedUnspecified by POSIX
BTIN-002Special builtin errors exit shellMay not exit on all casesConservative error handling
BTIN-010times shows CPU timesSynthetic timesNo process accounting
BTIN-021command -p uses default PATHSandbox PATHNo host PATH
BTIN-024wait for real PIDsVirtual jobs onlyNo real PIDs
BTIN-025kill sends to real processesVirtual PIDs onlySandbox isolation
EXIT-005Exit > 128 for signal deathTrapped signals onlyVirtual signal model
TRAP-002Signal handlers for all signalsSubset deliverableVirtual mechanism
TRAP-010Job control (bg, fg, jobs)Not implementedOut of scope
TRAP-011Monitor mode (set -m)No effectOut of scope
TRAP-012Job specificationsNot implementedOut of scope
TRAP-013SIGPIPE in pipelinesMay differVirtual pipeline model
ENV-007PATH controls command searchSource file lookup onlyRegistry model
ENV-015Dynamic scoping with unsetEdge cases differKnown limitation