%% GROUP Recorded from your messages
Your two decisions of 2026-11-02 on the page "Shell Large Subset".

%% GROUP Both shells accept it, but the results differ
The large subset rejects these today (alternative A), so `/bin/sh -c` runs them; G12 is the exception (a caller's option already, E). Each example below was run in both shells; output lines are separated by `|`, and an exit status is shown as `<…>` where it matters.

%% GROUP Already decided earlier
Three differences the subset already settles one way. They are listed so that every difference is on this page; the default here (no mark, or Go) is what was decided then; No-go is A.

%% GROUP Differences that show up only at run time
These cannot be rejected when the string is parsed, because the text does not show them. The default is rule A5 of the large spec: do what dash does. Alternative A means A5 here, and Go keeps it.

%% GROUP Bash-only syntax and builtins
dash rejects these, or treats them as an ordinary word or an unknown command. This group replaces item T1 ("a bash tier, later") of the page "Shell Large Subset".

@@ R1 | Recorded from your messages | A3 | Accept only what dash and bash run alike, and decide each difference on this page
## now
Your note on A3: it "should be accepted **and** a checklist of different features should be made, with all defaulting to 'as A3 says' if no choice is made yet."

## plan
Done: A3 (alternative A) stays in force, and this page lists the differences. Every item that you leave unmarked stays as A3 says: the large subset rejects the construct, and `/bin/sh -c` runs it. For the run-time group, the default is rule A5 (follow dash).

## nogo
Not applicable: this is your decision. Write in a note if I misread it.

## refs
Large spec, sections 2 and 5.

@@ R2 | Recorded from your messages | A4 | Use exit status 248 when something unsupported shows up only at run time, and document it
## now
Your note on A4: "2 is too common. What about 250-2=248? (These should be documented.)"

## plan
Done in the large spec; the executor patch is ready, not yet applied. When an unsupported construct shows up only at run time, the shell (or the subshell, `$( … )`, background job or pipeline element it shows up in) stops with status **248** after the message `ShellSubsetLarge: … is not supported`.

Example: `c=alias; $c ll=ls; echo after` prints `ShellSubsetLarge: 'alias' is not supported`, does not print `after`, and returns 248.

The number is documented in a new table "Exit statuses of the module itself" in the large spec, section 5. It is the only status the module makes up itself. Where the shell stops because dash would stop (rule A5), the status stays dash's.

The executor change is one line, in `claude/large-subset-a4-status.patch`, for the posix_spawn session to apply (tested on its bundle: status 248).

## nogo
Not applicable: this is your decision.

## refs
Large spec, section 5; `claude/large-subset-a4-status.patch`.

@@ G1 | Both shells accept it, but the results differ | local | `local NAME` without a value: choose (recommended: D)
## now
Example: `x=1; f(){ local x; echo "[$x]"; }; f`. dash: `[1]|<0>` (the local copy keeps the outer value). bash: `[]|<0>` (the local copy is unset).

Measured: 8 one-liners, 11 scripts.

## plan
Recommended D: follow whichever shell `/bin/sh` is. It costs one test in the executor, and scripts often declare `local x` before assigning it, where both shells agree anyway.

## nogo
A: rejected, as now.

## refs
`claude/large-subset-spec.md`, section 3, "Declarations".

@@ G2 | Both shells accept it, but the results differ | glob | Patterns that can match `.` and `..` (`.*`, `x/.?`): choose (recommended: D)
## now
Example, in a directory with a subdirectory `.h`: `echo .*`. dash: `. .. .h`. bash: `.h`. Rule U2 rejects such patterns.

Measured: 75 one-liners (`ls -d .*`, `du -sh .*`, `cp -r .* dir`), 2 scripts.

## plan
Recommended D: follow `/bin/sh`. The executor's file name expansion drops `.` and `..` or keeps them; one test.

## nogo
A: rejected, as now.

## refs
Large spec, section 2, U2.

@@ G3 | Both shells accept it, but the results differ | $@ | `$@` where it is not split into words (`x=$@`, `case "$@"`, `${x:=$@}`, here-documents): choose (recommended: A)
## now
Example: `set -- a b; IFS=:; x=$@; echo "$x"`. dash: `a:b` (joined with the first character of `IFS`). bash: `a b` (joined with blanks).

Measured: rare (not counted separately).

## plan
Recommended A: keep rejecting. Scripts that mean this write `"$*"`, which both shells agree on.

## nogo
A, as now.

## refs
Large spec, section 3, "`$@` only where it is split".

@@ G4 | Both shells accept it, but the results differ | $@ | `${@#p}`, `${*%p}`, `${#@}`, `${#*}`: choose (recommended: A)
## now
Example: `set -- ab cb; echo "${@#?}" "${*%b}"`. dash: `b cb ab c` (the pattern is removed once from the joined string). bash: `b b a c` (from each parameter).

Example: `set -- a b; echo ${#@} ${#*}`. dash: `3 3` (length of `a b`). bash: `2 2` (number of parameters).

Measured: only in ShellCheck's test snippets.

## plan
Recommended A: keep rejecting; rare, and both readings are plausible.

## nogo
A, as now.

## refs
Large spec, section 3, "Parameter forms".

@@ G5 | Both shells accept it, but the results differ | quoting | `\"` inside backquotes inside `"${…}"` or inside a here-document: choose (recommended: A)
## now
Example: ``echo "${x:-`echo \"q\"`}"``. dash: `q`. bash: `"q"`. Rule U3 rejects it.

## plan
Recommended A: keep rejecting; `$( … )` has no such problem.

## nogo
A, as now.

## refs
Large spec, section 2, U3.

@@ G6 | Both shells accept it, but the results differ | return | `return` outside a function: choose (recommended: D)
## now
Example: `echo a; return; echo b`. dash: `a|<0>` (it ends the string quietly). bash: `a`, then `return: can only 'return' from a function or sourced script`, `<2>`.

Measured: 9 scripts (ShellCheck's test snippets).

## plan
Recommended D: follow `/bin/sh`. Both shells stop there; only the message and the status differ.

## nogo
A: rejected, as now.

## refs
Large spec, section 3, "`return`".

@@ G7 | Both shells accept it, but the results differ | scope | `unset NAME` of a variable that a calling function made `local`: choose (recommended: A)
## now
Example: `x=g; f() { local x=1; g; echo "f:[$x]"; }; g() { unset x; echo "g:[$x]"; }; f`. dash: `g:[]|f:[]`. bash: `g:[g]|f:[g]` (the outer value shows through again).

## plan
Recommended A: keep rejecting; rare, and following bash needs a stack of values per variable.

## nogo
A, as now.

## refs
Large spec, section 3, "Declarations".

@@ G8 | Both shells accept it, but the results differ | vars | `$-` and `$LINENO`: choose (recommended: A)
## now
Example: `echo "[$-]"`. dash: `[]`. bash: `[hBc]`.

Example: `echo "[$LINENO]"`. dash: `[]` (in a `-c` string). bash: `[1]`.

Measured: 5 and 3 scripts.

## plan
Recommended A: keep rejecting.

## nogo
A, as now.

## refs
Base spec, section 5 (E1), the names a shell sets itself.

@@ G9 | Both shells accept it, but the results differ | set -x | `set -x` (print each command before running it): choose (recommended: A)
## now
Example: `set -x; echo "a b"`. dash prints `+ echo a b` to standard error; bash prints `+ echo 'a b'`. Item F6 of "Shell Large Subset" chose to reject it.

Measured: 2 one-liners, 3 scripts.

## plan
Recommended A: keep rejecting. Tracing needs about 20 lines in the executor, for each format.

## nogo
A, as now.

## refs
Large spec, section 3, the table of builtins (`set`).

@@ G10 | Both shells accept it, but the results differ | listing | The listing forms `set`, `set -o`, `export`, `export -p`, `readonly`, `readonly -p`, `trap`, `trap -p`: choose (recommended: A)
## now
They print variables, options or traps, in formats that differ. Example: `export ZZ=1; export -p | grep ZZ`. dash: `export ZZ='1'`. bash: `export ZZ="1"`. Example: `trap 'echo t' INT; trap`. bash also lists `trap -- '' TSTP` and the like.

Measured: `set` alone 18 one-liners, the others a few each.

## plan
Recommended A: keep rejecting; such output is read by people, not by programs.

## nogo
A, as now.

## refs
Large spec, section 3, the table of builtins.

@@ G11 | Both shells accept it, but the results differ | type | `type NAME` and `command -V NAME`: choose (recommended: D)
## now
For a program both print the same (`ls is /usr/bin/ls`). For a function or a builtin the text differs (dash: `f is a shell function`; bash also prints the function's body).

Measured: 4 one-liners, 5 scripts.

## plan
Recommended D: follow `/bin/sh`; about 15 lines in the executor.

## nogo
A: rejected, as now.

## refs
Large spec, section 3, `command`; X1 of "Shell Large Subset".

@@ G12 | Both shells accept it, but the results differ | fd | Descriptor numbers of two or more digits (`echo hi 10>/dev/null`): choose (recommended: E, as now)
## now
Example: `echo hi 10>/dev/null`. dash: nothing is printed (it reads `10` as an argument of `echo`, and `>/dev/null` as the redirection). bash: `hi` (descriptor 10 is redirected).

This is already alternative E: the caller's option `fdmulti` (rule D4) accepts it as bash reads it; without the option it is rejected.

## plan
Recommended: keep E.

## nogo
A: drop the option; always rejected.

## refs
Base spec, section 6, rule D4.

@@ G13 | Both shells accept it, but the results differ | redirect | `x >&2>f` and `echo hi >&f` (a target that dash reads differently): choose (recommended: A)
## now
Example: `echo x >&2>f; cat f`. dash: `Syntax error: redirection unexpected`, `<2>`. bash: `x`.

Example: `echo hi >&f; cat f`. dash: `Syntax error: Bad fd number`. bash: `hi`.

These are rules U4 and D3 (base spec).

## plan
Recommended A: keep rejecting; dash fails on both.

## nogo
A, as now.

## refs
Base spec, section 6, rule D3; large spec, section 2, U4.

@@ G14 | Both shells accept it, but the results differ | glob | `[^…]` in a pattern: choose (recommended: D)
## now
Example: `case b in [^a]) echo neg;; *) echo lit;; esac`. dash: `lit` (the `^` is an ordinary character there). bash: `neg` (negation, like `[!a]`). Rule V1 rejects it.

Measured: about 16 one-liners, 2 scripts.

## plan
Recommended D: follow `/bin/sh`; one test in the conversion of patterns.

## nogo
A: rejected, as now.

## refs
Base spec, section 2, V1.

@@ G15 | Both shells accept it, but the results differ | vars | Setting variables that bash makes read-only (`UID=5 cmd`, …), and reading `PS1`: choose (recommended: A)
## now
Example: `UID=5 echo hi`. dash: `hi`. bash: `UID: readonly variable`, `<1>`. Rule U5.

Example: `echo "[$PS1]"`. dash: `[# ]` (as root). bash: `[]`.

## plan
Recommended A: keep rejecting.

## nogo
A, as now.

## refs
Base spec, section 5 (E1, V8); large spec, section 2, U5.

@@ G16 | Both shells accept it, but the results differ | home | `~` and `cd` alone when `HOME` is not set: choose (recommended: A)
## now
Example: `unset HOME; echo ~`. dash: `~`. bash: `/root` (from the password file). Rule V10 rejects `~` when `HOME` is not in the environment.

## plan
Recommended A: keep rejecting. (If the string unsets `HOME` through a name from an expansion, as in `n=HOME; unset $n`, rule A5 applies: `~` then stays literal, as in dash; for `cd`, see N4.)

## nogo
A, as now.

## refs
Base spec, section 5, V10, and section 4, V15.

@@ G17 | Both shells accept it, but the results differ | functions | Functions named `local` or `source`: choose (recommended: A)
## now
Example: `local() { echo f; }; local`. dash: `Syntax error: Bad function name`. bash: `f`.

Example: `source() { echo f; }; source`. dash: `f`. bash: `` `source': is a special builtin``.

## plan
Recommended A: keep rejecting.

## nogo
A, as now.

## refs
Large spec, section 3, "Functions".

@@ G18 | Both shells accept it, but the results differ | read | `read -p PROMPT`: choose (recommended: B, which here equals C)
## now
Rejected: the large subset accepts `read` only with `-r`. Both shells accept `-p` and print the prompt to standard error only when standard input is a terminal. Example (input from a pipe): `echo x | { read -p 'p: ' v; echo "[$v]"; }`. dash: `[x]`. bash: `[x]`.

Measured: 52 one-liners, 8 scripts.

## plan
Recommended B: accept `read [-r] [-p PROMPT] NAME…`. The executor prints PROMPT to descriptor 2 when descriptor 0 is a terminal (about 3 lines). The parser needs about 2 lines.

## nogo
A: rejected, as now.

## refs
Base spec, section 4, `read`.

@@ K1 | Already decided earlier | time | `time` before a pipeline: stays as decided (dash's behaviour, B)
## now
Decided earlier (P5): `time` runs the program `time`, as dash does. bash's keyword `time` times the whole pipeline and prints its own report. Example: `time true 2>/dev/null; echo ok`. dash: `ok` only (the redirection applies to the program `time`, and with it to its report; on this machine there is no such program, so the "not found" message goes there too). bash: `real 0m0.000s`, `user …`, `sys …`, then `ok` (bash's report is not redirected, because `2>/dev/null` belongs to `true`).

Measured: 9 one-liners, 8 scripts.

## plan
No change unless you choose otherwise in a note: A (reject), C (bash's keyword), D (follow `/bin/sh`).

## nogo
A: reject `time` as a command name.

## refs
Base spec, section 1, P5.

@@ K2 | Already decided earlier | echo | `echo` with backslashes or `-e`: stays as decided (the program `/bin/echo`)
## now
Decided earlier (B2): `echo` runs as `/bin/echo`. dash's builtin turns `\t` and the like into characters (`echo 'a\tb'` prints a tab); bash's builtin does not, nor does GNU `/bin/echo`. `echo -e 'a\tb'`: bash and GNU `/bin/echo` print a tab; dash prints `-e a` and a tab.

So today the subset behaves as bash does, with GNU coreutils.

Measured: `echo -e`: 48 one-liners, 6 scripts.

## plan
No change unless you choose otherwise in a note: A (reject `echo` arguments with a backslash or starting with `-e`), B (dash's builtin), D (follow `/bin/sh`).

## nogo
A, as just described.

## refs
Base spec, section 4, B2.

@@ K3 | Already decided earlier | jobs | Job numbers such as `kill %1`: stays as decided (the program `kill`, as dash)
## now
Decided earlier (base spec section 4): `kill` runs as the program `kill` found in `PATH`, so job numbers do not work. Example: `sleep 1 & kill %1; echo $?`. dash: `kill: No such process`, `1` (dash's `kill` does not know job numbers either). bash: `0` (its `kill` signals job 1).

Measured: 2 one-liners.

## plan
No change unless you choose otherwise in a note: A (reject `kill` with an argument starting with `%`; one check in the parser), C (bash's job numbers), D (follow `/bin/sh`).

## nogo
A, as just described.

## refs
Base spec section 4, builtins.

@@ N1 | Differences that show up only at run time | errors | Errors of special builtins: `shift` past the end, `export` of a bad name, assignment to a read-only variable: choose (default: dash, A5)
## now
`shift 3; echo after`: dash stops, `<2>`; bash prints a message and goes on (`after`, `<0>`).

`n=1x; export "$n=2"; echo after`: dash stops, `<2>`; bash goes on.

`readonly r=1; r=2; echo after`: both stop; dash `<2>`, bash `<127>`.

## plan
Default A5: as dash. C: as bash. D: follow `/bin/sh`.

## nogo
As the default.

## refs
Large spec, section 5, A5.

@@ N2 | Differences that show up only at run time | status | The exit status after `${x:?message}` with `x` unset: choose (default: dash, 2)
## now
`echo ${zz:?unset}; echo after`: both print the message and stop; dash `<2>`, bash `<127>`.

## plan
Default A5: 2, as dash. C: 127. D: follow `/bin/sh`.

## nogo
As the default.

## refs
Large spec, section 5, A5.

@@ N3 | Differences that show up only at run time | command | The status of `command -v` for an unknown name: choose (default: dash, 127)
## now
`command -v nosuch; echo $?`: dash `127`, bash `1`.

## plan
Default A5: 127. C: 1. D: follow `/bin/sh`.

## nogo
As the default.

## refs
Large spec, section 5, A5.

@@ N4 | Differences that show up only at run time | cd | `cd` alone when `HOME` was unset by the string: choose (default: dash)
## now
`n=HOME; unset $n; cd; echo $?` (`unset HOME` written out is rejected when parsed, a name from an expansion is not): dash stays where it is, `0`. bash: `cd: HOME not set`, `1`.

## plan
Default A5: as dash. C: as bash. D: follow `/bin/sh`.

## nogo
As the default.

## refs
Large spec, section 5, A5.

@@ N5 | Differences that show up only at run time | getopts | `getopts` details: choose (default: dash)
## now
After a `getopts` loop has finished, a new `getopts` call: dash starts over, bash does not (L7). Example: `while getopts ab: o -a -b v; do :; done; getopts ab: o -b v; echo $? $o $OPTIND`. dash: `0 b 3`. bash: `1 ? 3`.

When no option is left, dash keeps `OPTARG`, bash unsets it (L8). Example: `getopts ab: o -b v; getopts ab: o -b v; echo "[$o] [$OPTARG] $OPTIND"`. dash: `[?] [v] 3`. bash: `[?] [] 3`.

## plan
Default A5, extended to these two cases: as dash (the executor does not yet do this; L7 and L8 in `claude/large-subset-upstream-reports.md`). C: as bash. D: follow `/bin/sh`.

## nogo
As the default.

## refs
`claude/large-subset-upstream-reports.md`, L7, L8.

@@ H1 | Bash-only syntax and builtins | [[ | `[[ … ]]`: choose (recommended: A)
## now
`[[ a == a* ]] && echo y`. dash: `[[: not found`, `<127>`. bash: `y`.

Measured: 21 one-liners, 123 scripts.

## plan
Recommended A for now. D (accept only when `/bin/sh` is bash) would cost about 60 lines in parser and executor (`==`, `=~`, `&&`, `||`, `!`, patterns, file tests).

## nogo
A, as now.

## refs
`claude/large-subset-investigation.md`, section 4.

@@ H2 | Bash-only syntax and builtins | arithmetic | `(( … ))`, `for ((…))`, `$[…]`, `++` and `--`, the comma operator: choose (recommended: A)
## now
`((x=1+1)); echo $x`. dash: an empty line (it reads `((…))` as two nested subshells that assign `x=1+1`; the assignment is lost with them). bash: `2`.

`i=1; echo $((i++)) $i`. dash: `expecting primary`, `<2>`. bash: `1 2`.

Measured: 5 one-liners, 75 scripts.

## plan
Recommended A for now; D would cost about 30 lines.

## nogo
A, as now.

## refs
Base spec, section 5, V9.

@@ H3 | Bash-only syntax and builtins | quoting | `$'…'` and `$"…"`: choose (recommended: A)
## now
``echo $'a\tb'``. dash: `$a` and a tab and `b` (it reads `$` literally, then `'a\tb'` with dash's `echo` turning `\t` into a tab). bash: `a`, a tab, `b`.

Measured: 136 one-liners, 14 scripts.

## plan
Recommended A for now; D costs about 15 lines (the escapes of `$'…'`).

## nogo
A, as now.

## refs
Base spec, section 2.

@@ H4 | Bash-only syntax and builtins | arrays | Arrays (`a=(x y)`, `${a[1]}`, `${a[@]}`, `$PIPESTATUS`): choose (recommended: A)
## now
`a=(x y); echo ${a[1]}`. dash: `Syntax error: "(" unexpected`. bash: `y`.

Measured: 46 one-liners, 138 scripts.

## plan
Recommended A for now; D would cost about 80 lines (indexed arrays only).

## nogo
A, as now.

## refs
`claude/large-subset-investigation.md`, section 4.

@@ H5 | Bash-only syntax and builtins | parameters | `${x/a/b}`, `${x:1:2}`, `${x^^}`, `${x,,}`, `${!x}`: choose (recommended: A)
## now
`x=abcd; echo ${x/b/X} ${x:1:2} ${x^^}`. dash: `Bad substitution`, `<2>`. bash: `aXcd bc ABCD`.

Measured: 15 one-liners, 55 scripts.

## plan
Recommended A for now; D would cost about 30 lines.

## nogo
A, as now.

## refs
Base spec, section 5, "Parameters".

@@ H6 | Bash-only syntax and builtins | redirect | Process substitution `<(…)` and `>(…)`: choose (recommended: A)
## now
`cat <(echo hi)`. dash: `Syntax error: "(" unexpected`. bash: `hi`.

Measured: 187 one-liners, 15 scripts: the most common bash-only construct in one-liners.

## plan
Recommended A for now. D would cost about 40 lines: the executor must pass a pipe as `/dev/fd/N`, which posix_spawn can do.

## nogo
A, as now.

## refs
Base spec, section 4.

@@ H7 | Bash-only syntax and builtins | redirect | Here-strings `<<<`: choose (recommended: A)
## now
`cat <<< hi`. dash: `Syntax error: redirection unexpected`. bash: `hi`.

Measured: 13 one-liners, 13 scripts.

## plan
Recommended A for now; D costs about 5 lines (a here-document whose body is the word plus a newline).

## nogo
A, as now.

## refs
Large spec, section 3, here-documents.

@@ H8 | Bash-only syntax and builtins | redirect | `&>file`, `&>>file`, `|&`: choose (recommended: A)
## now
`echo hi &>/dev/null; echo st=$?`. dash: `st=0`, then `hi` (it runs `echo hi` in the background and then `>/dev/null` as an empty command). bash: `st=0` only.

`echo hi |& cat`. dash: `Syntax error`. bash: `hi`.

Measured: 22 one-liners, 9 scripts.

## plan
Recommended A for now; D costs about 5 lines (as `>file 2>&1` and `2>&1 |`).

## nogo
A, as now.

## refs
Base spec, section 3, P2.

@@ H9 | Bash-only syntax and builtins | braces | Brace expansion (`a{b,c}`, `{1..3}`): choose (recommended: A)
## now
`echo a{b,c} {1..3}`. dash: `a{b,c} {1..3}`. bash: `ab ac 1 2 3`.

`ShellSubset` already has a parse-only option `brace` (base spec V13), which `ShellSubsetLarge` ignores; the executor cannot run its trees (known issue X3 in `claude/pspawn-known-issues.md`).

Measured: 62 one-liners, 17 scripts.

## plan
Recommended A for now; D costs about 20 lines in the executor.

## nogo
A, as now.

## refs
Base spec, section 4, V13.

@@ H10 | Bash-only syntax and builtins | functions | `function f { … }`: choose (recommended: A)
## now
`function f { echo f; }; f`. dash: `Syntax error`. bash: `f`.

Measured: 1 one-liner, 27 scripts.

## plan
Recommended A for now; D costs about 3 lines (the same tree as `f()`).

## nogo
A, as now.

## refs
Large spec, section 3, "Functions".

@@ H11 | Bash-only syntax and builtins | builtins | bash's builtins `source`, `declare`/`typeset`, `let`, `pushd`/`popd`/`dirs`, `shopt`, `mapfile`/`readarray`, `select`, `coproc`: choose (recommended: A)
## now
dash has none of them: `source ./s.sh` gives `source: not found`, `<127>`; bash runs the file. `declare -i n=1+2; echo $n`: dash `declare: not found` and an empty line; bash `3`.

Measured: 149 one-liners, 102 scripts.

## plan
Recommended A for now. `source` alone would cost 1 line (as `.`); the others 10–40 lines each.

## nogo
A, as now.

## refs
X1 of "Shell Large Subset".

@@ H12 | Bash-only syntax and builtins | read | `read` options other than `-r` and `-p`: `-d`, `-n`, `-s`, `-t`, `-a`, `-u`: choose (recommended: A)
## now
`printf 'a:b' | { read -d : v; echo "[$v]"; }`. dash: `read: Illegal option -d`, `[]`. bash: `[a]`.

Measured: 78 one-liners, 27 scripts, including those that use only `-p` (G18).

## plan
Recommended A for now; D costs about 20 lines.

## nogo
A, as now.

## refs
Base spec, section 4, `read`.

@@ H13 | Bash-only syntax and builtins | set | `set -o pipefail`: choose (recommended: A)
## now
`set -o pipefail; false | true; echo $?`. dash 0.5.12: `set: Illegal option -o pipefail`, `<2>`. bash: `1`.

Measured: 2 one-liners, 21 scripts.

## plan
Recommended A for now; D costs about 5 lines (the executor already has every element's status).

## nogo
A, as now.

## refs
Large spec, section 3, `set`.

@@ H14 | Bash-only syntax and builtins | vars | Reading bash's own variables `RANDOM`, `SECONDS`, `EPOCHSECONDS`, `BASH_VERSION`, `BASHPID`, `EUID`, `UID`, `FUNCNAME`, … (setting them is G15): choose (recommended: A)
## now
`echo ${RANDOM:+set}`. dash: an empty line. bash: `set`.

Measured: 20 one-liners, 28 scripts.

## plan
Recommended A for now; D costs a few lines per variable.

## nogo
A, as now.

## refs
Base spec, section 5 (E1).
