name: "Special parameters" cases: - name: "$_ - initial value matches $0" stdin: | [[ "$0" == "$_" ]] && echo "matches on start" - name: "$_ - last argument tracked across simple commands" stdin: | : one echo "[$_]" : two three four echo "[$_]" echo last_echo_arg echo "[$_]" - name: "$_ - zero-arg command uses command name" stdin: | echo seed1 seed2 : echo "after colon: [$_]" true echo "after true: [$_]" echo echo "after bare echo: [$_]" - name: "$_ - args with spaces and special chars" stdin: | echo "seed last" echo "[$_]" echo "arg with spaces" 'arg-with-dashes' "arg:with:colons" echo "[$_]" echo "" trailing echo "[$_]" - name: "$_ - builtin dispatch path" stdin: | echo seed last : bu1 bu2 bu3 echo "[$_]" printf '%s\n' pf1 pf2 echo "[$_]" - name: "$_ - external command dispatch path" stdin: | echo seed last /usr/bin/true ext1 ext2 echo "[$_]" /usr/bin/env ENV=1 /usr/bin/true external_final echo "[$_]" - name: "$_ - external command exports resolved path via env" stdin: | # When invoking an external command, it should see _ set # to the resolved pathname of the command (not "last arg"). /usr/bin/env | grep '^_=' - name: "$_ - function dispatch sets to call-site last arg" stdin: | f() { :; } echo seed_last f call_a call_b echo "[$_]" - name: "$_ - function body sees pre-invocation value on entry" stdin: | f() { echo "entry: [$_]" echo new_inner echo "after inner echo: [$_]" } echo pre_seed f call_arg echo "after return: [$_]" - name: "$_ - nested function dispatch" stdin: | inner() { echo innerdone; } outer() { inner ia ib; } echo seed outer oa ob echo "[$_]" - name: "$_ - assignment-only function body" stdin: | f() { a=1; b=2; } echo seed_last f foo bar echo "[$_]" - name: "$_ - cleared by assignment-only statements" stdin: | echo seed_last x=assigned echo "after assign: [$_]" y=another echo "after second assign: [$_]" : colonarg echo "after colon: [$_]" - name: "$_ - cleared by assignment with command substitution" stdin: | echo seed_last z=$(echo subst_inner) echo "after assignment: [$_]" - name: "$_ - single-stage pipeline does not update parent" stdin: | echo prev_a prev_b echo pipe_a pipe_b | cat echo "[$_]" - name: "$_ - multi-stage pipeline does not update parent" stdin: | echo prev_a prev_b echo pipe_a pipe_b | cat | cat echo "[$_]" - name: "$_ - and-chain tracks last arg of last executed command" stdin: | echo seed_last true && echo a1 a2 echo "[$_]" true && true t1 t2 echo "[$_]" - name: "$_ - or-chain tracks last arg of last executed command" stdin: | echo seed_last false || echo or1 or2 echo "[$_]" - name: "$_ - command-not-found update" ignore_stderr: true stdin: | echo seed_last nosuchcmd_xyzzy fail_a fail_b echo "[$_]" - name: "$_ - for loop body" stdin: | echo seed_last for i in 1 2 3; do :; done echo "[$_]" for i in a b c; do echo "loop $i"; done echo "[$_]" - name: "$_ - while loop body" stdin: | echo seed_last i=0 while [ $i -lt 2 ]; do echo "iter $i"; i=$((i+1)); done echo "[$_]" - name: "$_ - until loop body" stdin: | echo seed_last i=0 until [ $i -ge 2 ]; do i=$((i+1)); done echo "[$_]" - name: "$_ - if/then body" stdin: | echo seed_last if true; then echo then_a then_b; fi echo "[$_]" - name: "$_ - case body" stdin: | echo seed_last case x in x) echo match_a match_b ;; esac echo "[$_]" - name: "$_ - eval tracks eval's last arg" stdin: | echo seed_last eval "echo evaled one two" echo "[$_]" - name: "$_ - source tracks sourced script's commands" test_files: - path: sourced.sh contents: | echo sourced_a sourced_b stdin: | echo seed_last . ./sourced.sh echo "[$_]" - name: "$_ - subshell does not leak into parent" stdin: | echo outer_a outer_b (echo inner1 inner2; echo "sub: [$_]") echo "parent: [$_]" - name: "$_ - background job + wait" stdin: | echo seed_last (:) & wait echo "[$_]" - name: "$_ - exported attribute after update" stdin: | export _=initial_value echo first last # After commands have run, does _ still have the -x attribute? declare -p _ | grep -c '^declare -x' - name: "$_ - declare -p reflects updated value" stdin: | export _=initial_value echo first last declare -p _ - name: "$_ - readonly is honored" ignore_stderr: true stdin: | readonly _=frozen echo hi there echo "[$_]" - name: "$_ - exec does not override _ in child env" known_failure: true # exec builtin goes through compose_std_command which unconditionally sets _ stdin: | # bash does not set _ in the child's env for exec; the child inherits # the parent's _ value. brush currently sets _ to the resolved command # path (same as a normal external command), which is wrong for exec. (exec /usr/bin/env) | grep '^_=' - name: "$@ and $*" stdin: | function myfunc() { echo "--myfunc called--" echo "COUNT: $#" echo "AT-SIGN VALUE: '$@'" echo "STAR VALUE: '$*'" for arg in $@; do echo "AT-SIGN ELEMENT: '${arg}'" done for arg in $*; do echo "STAR ELEMENT: '${arg}'" done for arg in "$@"; do echo "DOUBLE-QUOTED AT-SIGN ELEMENT: '${arg}'" done for arg in "$*"; do echo "DOUBLE-QUOTED STAR ELEMENT: '${arg}'" done } myfunc myfunc 1 myfunc 1 2 myfunc "a b c" 2