xref: /aosp_15_r20/external/toybox/tests/sh.test (revision cf5a6c84e2b8763fc1a7db14496fd4742913b199)
1*cf5a6c84SAndroid Build Coastguard Worker#!/bin/echo no
2*cf5a6c84SAndroid Build Coastguard Worker
3*cf5a6c84SAndroid Build Coastguard Worker[ -f testing.sh ] && . testing.sh
4*cf5a6c84SAndroid Build Coastguard Worker
5*cf5a6c84SAndroid Build Coastguard Worker# TODO make fake pty wrapper for test infrastructure
6*cf5a6c84SAndroid Build Coastguard Worker
7*cf5a6c84SAndroid Build Coastguard Worker# testing "name" "command" "result" "infile" "stdin"
8*cf5a6c84SAndroid Build Coastguard Worker# texpect "name" "command" [R]I/O/E"string" X[ERR]
9*cf5a6c84SAndroid Build Coastguard Worker
10*cf5a6c84SAndroid Build Coastguard Worker# Use "bash" name for host, "sh" for toybox. (/bin/sh is often defective.)
11*cf5a6c84SAndroid Build Coastguard Worker[ -z "$SH" ] && { [ -z "$TEST_HOST" ] && SH="sh" || export SH="bash" ; }
12*cf5a6c84SAndroid Build Coastguard Worker# The expected prompt is different for root vs normal user
13*cf5a6c84SAndroid Build Coastguard Worker[ $UID -eq 0 ] && P='# ' || P='$ '
14*cf5a6c84SAndroid Build Coastguard Worker# insulate shell child process to get predictable results
15*cf5a6c84SAndroid Build Coastguard WorkerSS="env -i PATH=${PATH@Q} PS1='\\$ ' $SH --noediting --noprofile --norc -is"
16*cf5a6c84SAndroid Build Coastguard Worker
17*cf5a6c84SAndroid Build Coastguard Worker[ -z "$TEST_HOST" ] && : ${BROKEN=true}
18*cf5a6c84SAndroid Build Coastguard Worker# Wrap txpect for shell testing
19*cf5a6c84SAndroid Build Coastguard Workershxpect() {
20*cf5a6c84SAndroid Build Coastguard Worker  X="$1"
21*cf5a6c84SAndroid Build Coastguard Worker  shift
22*cf5a6c84SAndroid Build Coastguard Worker  txpect "$X" "$SS" E"$P" "$@" X0
23*cf5a6c84SAndroid Build Coastguard Worker}
24*cf5a6c84SAndroid Build Coastguard Worker
25*cf5a6c84SAndroid Build Coastguard Workershxpect "prompt and exit" I$'exit\n'
26*cf5a6c84SAndroid Build Coastguard Workershxpect "prompt and echo" I$'echo hello\n' O$'hello\n' E"$P"
27*cf5a6c84SAndroid Build Coastguard Workershxpect "redir" I$'cat<<<hello\n' O$'hello\n' E"$P"
28*cf5a6c84SAndroid Build Coastguard Workershxpect "redirect err" I$'echo > /dev/full\n' E E"$P" X1
29*cf5a6c84SAndroid Build Coastguard Workershxpect "wait for <(exit)" I$'cat <(echo hello 1>&2)\n' E$'hello\n' E"$P"
30*cf5a6c84SAndroid Build Coastguard Worker
31*cf5a6c84SAndroid Build Coastguard Worker# Test shell command line (-c and how scripts run) before changing EVAL
32*cf5a6c84SAndroid Build Coastguard Workertesting '-c "" exit status 0' '$SH -c "" && echo $?' '0\n' '' ''
33*cf5a6c84SAndroid Build Coastguard Workertesting '-c args' "\$SH -c 'echo \$0,\$1,\$2,\$3' one two three four five" \
34*cf5a6c84SAndroid Build Coastguard Worker  "one,two,three,four\n" "" ""
35*cf5a6c84SAndroid Build Coastguard Workertesting '-c args2' "\$SH -c 'echo \${10}' a b c d e f g h i j k l" "k\n" "" ""
36*cf5a6c84SAndroid Build Coastguard Workertesting '-c arg split' \
37*cf5a6c84SAndroid Build Coastguard Worker  "$SH -c 'for i in a\"\$@\"b;do echo =\$i=;done;echo \$0' 123 456 789" \
38*cf5a6c84SAndroid Build Coastguard Worker  "=a456=\n=789b=\n123\n" "" ""
39*cf5a6c84SAndroid Build Coastguard Workertesting '-c arg split2' \
40*cf5a6c84SAndroid Build Coastguard Worker  "$SH -c 'for i in a\"\$* \$@\"b; do echo =\$i=;done' one two three four five"\
41*cf5a6c84SAndroid Build Coastguard Worker  "=atwo three four five two=\n=three=\n=four=\n=fiveb=\n" "" ""
42*cf5a6c84SAndroid Build Coastguard Workertesting '-c arg count' "$SH -c 'echo \$#' 9 8 7 6 1 2 3 4" "7\n" "" ""
43*cf5a6c84SAndroid Build Coastguard Workertesting 'trailing \' "$SH -c 'echo \'" '\\\n' '' ''
44*cf5a6c84SAndroid Build Coastguard Workertesting "trailing \\ in ''" "$SH -c \$'echo \\'one\\\\\\ntwo\\''" \
45*cf5a6c84SAndroid Build Coastguard Worker  'one\\\ntwo\n' '' ''
46*cf5a6c84SAndroid Build Coastguard Workertesting 'trailing \ in ""' "$SH -c \$'echo \"one\\\\\\ntwo\"'" 'onetwo\n' \
47*cf5a6c84SAndroid Build Coastguard Worker  '' ''
48*cf5a6c84SAndroid Build Coastguard Workertesting 'vanishing \' "$SH -c \$'echo \\\\\\n a'" 'a\n' '' ''
49*cf5a6c84SAndroid Build Coastguard Workertesting 'command\ arg' "$SH -c \$'echo\\\\\\n  abc'" 'abc\n' '' ''
50*cf5a6c84SAndroid Build Coastguard Workertesting "exec3" '$C -c "{ exec readlink /proc/self/fd/0;} < /proc/self/exe"' \
51*cf5a6c84SAndroid Build Coastguard Worker  "$(readlink -f $C)\n" "" ""
52*cf5a6c84SAndroid Build Coastguard Workertesting 'arg shift' "$SH -c '"'for i in "" 2 1 1 1; do echo $? $1; shift $i; done'"' one two three four five" \
53*cf5a6c84SAndroid Build Coastguard Worker  "0 two\n0 three\n0 five\n0\n1\n" "" ""
54*cf5a6c84SAndroid Build Coastguard Workertesting '(subshell)' '$SH -c "(echo hello)"' 'hello\n' '' ''
55*cf5a6c84SAndroid Build Coastguard Workertesting 'syntax' '$SH -c "if true; then echo hello | fi" 2>/dev/null || echo x'\
56*cf5a6c84SAndroid Build Coastguard Worker  'x\n' '' ''
57*cf5a6c84SAndroid Build Coastguard Workertesting 'syntax2' '$SH -c "for;i 0" 2>&1 | { grep -qi syntax && echo yes; }' \
58*cf5a6c84SAndroid Build Coastguard Worker  'yes\n' '' ''
59*cf5a6c84SAndroid Build Coastguard Worker
60*cf5a6c84SAndroid Build Coastguard Worker# The bash man page is lying when it says $_ starts with an absolute path.
61*cf5a6c84SAndroid Build Coastguard Workerln -s "$(which $SH)" bash
62*cf5a6c84SAndroid Build Coastguard Workertesting 'non-absolute $_' "./bash -c 'echo \$_'" './bash\n' '' ''
63*cf5a6c84SAndroid Build Coastguard Workerrm bash
64*cf5a6c84SAndroid Build Coastguard Worker
65*cf5a6c84SAndroid Build Coastguard Workertesting 'exec exitval' "$SH -c 'exec echo hello' && echo \$?" "hello\n0\n" "" ""
66*cf5a6c84SAndroid Build Coastguard Workertesting 'simple script' '$SH input' 'input\n' 'echo $0' ''
67*cf5a6c84SAndroid Build Coastguard Workertesting 'simple script2' '$SH ./input two;echo $?' './input+two\n42\n' \
68*cf5a6c84SAndroid Build Coastguard Worker  '\necho $0+$1\n\nexit 42' ''
69*cf5a6c84SAndroid Build Coastguard Worker# this segfaults bash
70*cf5a6c84SAndroid Build Coastguard Workertoyonly testing 'recursion guard' \
71*cf5a6c84SAndroid Build Coastguard Worker  '$SH input 2>/dev/null; [ $? -lt 128 ] && echo pass' 'pass\n' \
72*cf5a6c84SAndroid Build Coastguard Worker  'source input' ''
73*cf5a6c84SAndroid Build Coastguard Workertesting '$LINENO 1' "$SH input" "1\n" 'echo $LINENO' ''
74*cf5a6c84SAndroid Build Coastguard Worker
75*cf5a6c84SAndroid Build Coastguard Workermkdir sub
76*cf5a6c84SAndroid Build Coastguard Workerecho echo hello > sub/script
77*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing 'simple script in $PATH' "PATH='$PWD/sub:$PATH' $SH script" \
78*cf5a6c84SAndroid Build Coastguard Worker  'hello\n' '' ''
79*cf5a6c84SAndroid Build Coastguard Workerrm -rf sub
80*cf5a6c84SAndroid Build Coastguard Worker
81*cf5a6c84SAndroid Build Coastguard Workertesting "script file" "chmod +x input; ./input" "hello\n" "#!$C\necho hello" ""
82*cf5a6c84SAndroid Build Coastguard Workertesting 'IFS $*' "$SH -c 'IFS=xy; echo \"\$*\"' one two tyree" "twoxtyree\n" \
83*cf5a6c84SAndroid Build Coastguard Worker  "" ""
84*cf5a6c84SAndroid Build Coastguard Worker# Without the \n\n bash 5 emits SHLVL=0
85*cf5a6c84SAndroid Build Coastguard Workertesting 'default exports' \
86*cf5a6c84SAndroid Build Coastguard Worker  "env -i \"$(which $SH)\" --noprofile --norc -c \$'env\n\n' | sort" \
87*cf5a6c84SAndroid Build Coastguard Worker  "PWD=$(pwd)\nSHLVL=1\n_=$(which env)\n" "" ""
88*cf5a6c84SAndroid Build Coastguard Worker# toysh order of operations not matching bash
89*cf5a6c84SAndroid Build Coastguard Worker#testing "leading assignment fail" \
90*cf5a6c84SAndroid Build Coastguard Worker#  "{ \$SH -c 'X=\${a?blah} > walroid';ls walroid;} 2>/dev/null" '' '' ''
91*cf5a6c84SAndroid Build Coastguard Workertesting "lineno" "$SH input" "5 one\n6 one\n5 two\n6 two\n" \
92*cf5a6c84SAndroid Build Coastguard Worker  '#!/bin/bash\n\nfor i in one two\ndo\n  echo $LINENO $i\n  echo $LINENO $i\ndone\n' ""
93*cf5a6c84SAndroid Build Coastguard Workertesting "eval0" "$SH -c 'eval echo \$*' one two three" "two three\n" "" ""
94*cf5a6c84SAndroid Build Coastguard Worker
95*cf5a6c84SAndroid Build Coastguard Worker#########################################################################
96*cf5a6c84SAndroid Build Coastguard Worker# Change EVAL to call sh -c for us, using "bash" explicitly for the host.
97*cf5a6c84SAndroid Build Coastguard Workerexport EVAL="timeout 10 $SH -c"
98*cf5a6c84SAndroid Build Coastguard Worker
99*cf5a6c84SAndroid Build Coastguard Worker# From here on, tests run within the new shell by default.
100*cf5a6c84SAndroid Build Coastguard Worker
101*cf5a6c84SAndroid Build Coastguard Workertesting 'return code' 'if false; then echo true; fi; echo $?' '0\n' '' ''
102*cf5a6c84SAndroid Build Coastguard Workertesting 'return code 2' 'if true; then false; fi; echo $?' '1\n' '' ''
103*cf5a6c84SAndroid Build Coastguard Workertesting 'return code 3' 'x=0; while [ $((x++)) -lt 2 ]; do echo $x; done; echo $?' '1\n2\n0\n' '' ''
104*cf5a6c84SAndroid Build Coastguard Workertesting 'return code 4' 'false; A=B; echo $?' '0\n' '' ''
105*cf5a6c84SAndroid Build Coastguard Workertesting 'local var +whiteout' \
106*cf5a6c84SAndroid Build Coastguard Worker  'l=X;x(){ local l=47; echo $l;unset l; echo l=$l;};x;echo $l' '47\nl=\nX\n' \
107*cf5a6c84SAndroid Build Coastguard Worker  '' ''
108*cf5a6c84SAndroid Build Coastguard Workertesting 'escape passthrough' 'echo -e "a\nb\nc\td"' 'a\nb\nc\td\n' '' ''
109*cf5a6c84SAndroid Build Coastguard Worker
110*cf5a6c84SAndroid Build Coastguard Workertesting 'trailing $ is literal' 'echo $' '$\n' '' ''
111*cf5a6c84SAndroid Build Coastguard Workertesting 'work after HERE' $'cat<<0;echo hello\npotato\n0' 'potato\nhello\n' '' ''
112*cf5a6c84SAndroid Build Coastguard Workertesting '<<\EOF' $'(cat<<EOF\n$PATH\nEOF\necho "$PATH") | sort -u | wc -l' \
113*cf5a6c84SAndroid Build Coastguard Worker  '1\n' '' ''
114*cf5a6c84SAndroid Build Coastguard Workertesting "<<EOF''" $'(cat<<EOF\'\'\n$PATH\nEOF\necho "$PATH") | sort -u | wc -l'\
115*cf5a6c84SAndroid Build Coastguard Worker  '2\n' '' ''
116*cf5a6c84SAndroid Build Coastguard Workertesting '<<\EOF' $'(cat<<\\EOF\n$PATH\nEOF\necho "$PATH") | sort -u | wc -l' \
117*cf5a6c84SAndroid Build Coastguard Worker  '2\n' '' ''
118*cf5a6c84SAndroid Build Coastguard Workertesting '<< \' $'cat<<EOF\nabc\\\ndef\nEOF\n' 'abcdef\n' '' ''
119*cf5a6c84SAndroid Build Coastguard Workertesting '<< "\"' $'cat<<\\EOF\nabc\\\ndef\nEOF\n' 'abc\\\ndef\n' '' ''
120*cf5a6c84SAndroid Build Coastguard Workertesting '<<""' $'cat<<"";echo hello\npotato\n\necho huh' 'potato\nhello\nhuh\n'\
121*cf5a6c84SAndroid Build Coastguard Worker  '' ''
122*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing '<< trailing \' $'cat<<EOF 2>/dev/null\nabcde\nnext\\\nEOF\nEOF' \
123*cf5a6c84SAndroid Build Coastguard Worker  'abcde\nnextEOF\n' '' ''
124*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing '<< trailing \ 2' $'cat<<EOF\nabcde\nEO\\\nF\necho hello' \
125*cf5a6c84SAndroid Build Coastguard Worker  'abcde\nhello\n' '' ''
126*cf5a6c84SAndroid Build Coastguard Workertesting '<< $(a)' $'cat<<$(a)\nx\n$(a)' 'x\n' '' ''
127*cf5a6c84SAndroid Build Coastguard Workertesting 'HERE straddle' $'cat<<EOF;if true\nhello\nEOF\nthen echo also; fi' \
128*cf5a6c84SAndroid Build Coastguard Worker  'hello\nalso\n' '' ''
129*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing '\\n in <<EOF' $'cat<<EO\\\nF\n$PATH\nEOF\n' "$PATH\n" "" ""
130*cf5a6c84SAndroid Build Coastguard Workertesting '\\n in <<EOF with ""' $'cat<<EO\\\nF""\n$PATH\nEOF\n' '$PATH\n' '' ''
131*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing '\\n in HERE terminator' $'cat<<EOF\nabc\nE\\\nOF\necho hello\n' \
132*cf5a6c84SAndroid Build Coastguard Worker  'abc\nhello\n' '' ''
133*cf5a6c84SAndroid Build Coastguard Workerln -s "$(which echo)" echo2
134*cf5a6c84SAndroid Build Coastguard Workertesting "undelimited redirect doesn't eat prefix" './echo2</dev/null hello' \
135*cf5a6c84SAndroid Build Coastguard Worker  'hello\n' '' ''
136*cf5a6c84SAndroid Build Coastguard Workerrm -f echo2
137*cf5a6c84SAndroid Build Coastguard Workertesting 'prefix assignment is local' '{ echo $ABC; } {ABC}</dev/null; echo $3'\
138*cf5a6c84SAndroid Build Coastguard Worker  '10\n\n' '' ''
139*cf5a6c84SAndroid Build Coastguard Workertesting 'double quotes' 'echo \x "\x" "\\" "\$" "\`"' 'x \x \ $ `\n' '' ''
140*cf5a6c84SAndroid Build Coastguard Workertesting 'quoted line escapes' $'echo "\\\none" \'\\\ntwo\'' 'one \\\ntwo\n' '' ''
141*cf5a6c84SAndroid Build Coastguard Workertesting 'escape makes argument' 'echo \  | wc -c' '2\n' '' ''
142*cf5a6c84SAndroid Build Coastguard Worker
143*cf5a6c84SAndroid Build Coastguard Worker# TODO testing 'empty +() is literal' 'echo +()' '+()\n' '' ''
144*cf5a6c84SAndroid Build Coastguard Worker
145*cf5a6c84SAndroid Build Coastguard Worker# shxpect "EOF" I$'<<EOF;echo hello'
146*cf5a6c84SAndroid Build Coastguard Workershxpect 'queued work after HERE' I$'<<0;echo hello\n' E"> " I$'0\n' O$'hello\n'
147*cf5a6c84SAndroid Build Coastguard Workershxpect '$_ preserved on assignment error' I$'true hello; a=1 b=2 c=${}\n' \
148*cf5a6c84SAndroid Build Coastguard Worker  E E"$P" I$'echo $_\n' O$'hello\n'
149*cf5a6c84SAndroid Build Coastguard Workershxpect '$_ preserved on prefix error' I$'true hello; a=1 b=2 c=${} true\n' \
150*cf5a6c84SAndroid Build Coastguard Worker  E E"$P" I$'echo $_\n' O$'hello\n'
151*cf5a6c84SAndroid Build Coastguard Workershxpect '$_ preserved on exec error' I$'true hello; ${}\n' \
152*cf5a6c84SAndroid Build Coastguard Worker  E E"$P" I$'echo $_\n' O$'hello\n'
153*cf5a6c84SAndroid Build Coastguard Workershxpect '$_ abspath on exec' I$'env | grep ^_=\n' O$'_=/usr/bin/env\n'
154*cf5a6c84SAndroid Build Coastguard Workertesting '$_ literal after exec' 'env >/dev/null; echo $_' 'env\n' '' ''
155*cf5a6c84SAndroid Build Coastguard Workershxpect '$_ no path for builtin' I$'true; echo $_\n' O$'true\n'
156*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing 'prefix is local for builtins' 'abc=123; abc=def unset abc; echo $abc' \
157*cf5a6c84SAndroid Build Coastguard Worker  '123\n' '' ''
158*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing 'prefix localizes magic vars' \
159*cf5a6c84SAndroid Build Coastguard Worker  'SECONDS=123; SECONDS=345 true; echo $SECONDS' '123\n' '' ''
160*cf5a6c84SAndroid Build Coastguard Workershxpect 'body evaluated before variable exports' I$'a=x${} y${}\n' RE'y${}' X1
161*cf5a6c84SAndroid Build Coastguard Workertesting '$NOTHING clears $_' 'true; $NOTHING; echo $_' '\n' '' ''
162*cf5a6c84SAndroid Build Coastguard Workertesting 'assignment with redirect is persistent, not prefix' \
163*cf5a6c84SAndroid Build Coastguard Worker  'ABC=DEF > potato && rm potato && echo $ABC' 'DEF\n' '' ''
164*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing '$_ with functions' 'true; x(){ echo $_;}; x abc; echo $_' \
165*cf5a6c84SAndroid Build Coastguard Worker  'true\nabc\n' '' ''
166*cf5a6c84SAndroid Build Coastguard Worker
167*cf5a6c84SAndroid Build Coastguard Workermkdir -p one/two/three
168*cf5a6c84SAndroid Build Coastguard Workertesting 'cd in renamed dir' \
169*cf5a6c84SAndroid Build Coastguard Worker  'cd one/two/three && mv ../../../{one,four} && cd .. && echo ${PWD: -9:9}' \
170*cf5a6c84SAndroid Build Coastguard Worker  '/four/two\n' '' ''
171*cf5a6c84SAndroid Build Coastguard Workerrm -rf one
172*cf5a6c84SAndroid Build Coastguard Worker
173*cf5a6c84SAndroid Build Coastguard Workertesting "smoketest" "echo hello" "hello\n" "" ""
174*cf5a6c84SAndroid Build Coastguard Workertesting "assignment" 'x=y; echo $x' 'y\n' '' ''
175*cf5a6c84SAndroid Build Coastguard Workertesting "+= assignment" 'x+=abc; y=def; y+=$x; echo $y' 'defabc\n' '' ''
176*cf5a6c84SAndroid Build Coastguard Workertesting "eval" "eval echo hello" "hello\n" "" ""
177*cf5a6c84SAndroid Build Coastguard Workertesting "eval2" "eval 'echo hello'; echo $?" "hello\n0\n" "" ""
178*cf5a6c84SAndroid Build Coastguard Workertesting "eval3" 'X="echo hello"; eval "$X"' "hello\n" "" ""
179*cf5a6c84SAndroid Build Coastguard Workertesting "eval4" 'eval printf '=%s=' \" hello \"' "= hello =" "" ""
180*cf5a6c84SAndroid Build Coastguard WorkerNOSPACE=1 testing "eval5" 'eval echo \" hello \" | wc' ' 1 1 8' "" ""
181*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing 'eval6' $'false; eval \'echo $?\'' '1\n' '' ''
182*cf5a6c84SAndroid Build Coastguard Workertesting 'eval7' $'eval \'false\'; echo $?' '1\n' '' ''
183*cf5a6c84SAndroid Build Coastguard Workertesting 'eval8' $'false; eval ''; echo $?' '0\n' '' ''
184*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing 'eval9' $'A=echo; false; eval \'$A $?\'' '1\n' '' ''
185*cf5a6c84SAndroid Build Coastguard Workertesting "exec" "exec echo hello" "hello\n" "" ""
186*cf5a6c84SAndroid Build Coastguard Workertesting "exec2" "exec echo hello; echo $?" "hello\n" "" "" 
187*cf5a6c84SAndroid Build Coastguard Worker
188*cf5a6c84SAndroid Build Coastguard Worker# ; | && ||
189*cf5a6c84SAndroid Build Coastguard Workertesting "semicolon" "echo one;echo two" "one\ntwo\n" "" ""
190*cf5a6c84SAndroid Build Coastguard Workertesting "simple pipe" "echo hello | cat" "hello\n" "" ""
191*cf5a6c84SAndroid Build Coastguard Workertesting "&&" "true && echo hello" "hello\n" "" ""
192*cf5a6c84SAndroid Build Coastguard Workertesting "&&2" "false && echo hello" "" "" ""
193*cf5a6c84SAndroid Build Coastguard Workertesting "||" "true || echo hello" "" "" ""
194*cf5a6c84SAndroid Build Coastguard Workertesting "||2" "false || echo hello" "hello\n" "" ""
195*cf5a6c84SAndroid Build Coastguard Workertesting "&& ||" "true && false && potato || echo hello" "hello\n" "" ""
196*cf5a6c84SAndroid Build Coastguard Workertesting "&& after function" "x(){ false;};x && echo yes" "" "" ""
197*cf5a6c84SAndroid Build Coastguard Workertesting "|| after function" "x(){ false;};x || echo yes" "yes\n" "" ""
198*cf5a6c84SAndroid Build Coastguard Worker
199*cf5a6c84SAndroid Build Coastguard Worker# redirection
200*cf5a6c84SAndroid Build Coastguard Worker
201*cf5a6c84SAndroid Build Coastguard Workertesting "redir1" "cat < input" "hello\n" "hello\n" ""
202*cf5a6c84SAndroid Build Coastguard Workertesting "redir2" "echo blah >out; cat out" "blah\n" "" ""
203*cf5a6c84SAndroid Build Coastguard Workertesting "redir3" "echo more >>out; cat out" "blah\nmore\n" "" ""
204*cf5a6c84SAndroid Build Coastguard Workertesting "redir4" "touch /not/exist 2>out||grep -o /not/exist out" \
205*cf5a6c84SAndroid Build Coastguard Worker  "/not/exist\n" "" ""
206*cf5a6c84SAndroid Build Coastguard Workertesting "redir5" "ls out /not/exist &> out2 || wc -l < out2" "2\n" "" ""
207*cf5a6c84SAndroid Build Coastguard Workertesting "redir6" "ls out /not/exist &>>-abc || wc -l < ./-abc" "2\n" "" ""
208*cf5a6c84SAndroid Build Coastguard Workertesting "redir7" "ls out /not/exist |& wc -l" "2\n" "" ""
209*cf5a6c84SAndroid Build Coastguard Workertesting "redir8" 'echo -n $(<input)' "boing" "boing\n" ""
210*cf5a6c84SAndroid Build Coastguard Workershxpect "redir9" I$'echo hello > out 2>/does/not/exist\n' E E"$P" \
211*cf5a6c84SAndroid Build Coastguard Worker  I$'wc -l < out\n' O$'0\n'
212*cf5a6c84SAndroid Build Coastguard Workertesting "redir10" 'echo hello 3<&3' "hello\n" "" ""
213*cf5a6c84SAndroid Build Coastguard Workertesting "redir11" 'if :;then echo one;fi {abc}<input; cat <&$abc' \
214*cf5a6c84SAndroid Build Coastguard Worker  "one\npotato\n" "potato\n" ""
215*cf5a6c84SAndroid Build Coastguard Workerrm -f out out2 ./-abc
216*cf5a6c84SAndroid Build Coastguard Worker
217*cf5a6c84SAndroid Build Coastguard Worker# expansion
218*cf5a6c84SAndroid Build Coastguard Worker
219*cf5a6c84SAndroid Build Coastguard Workertesting "tilde expansion" "echo ~" "$HOME\n" "" ""
220*cf5a6c84SAndroid Build Coastguard Workertesting "tilde2" "echo ~/dir" "$HOME/dir\n" "" ""
221*cf5a6c84SAndroid Build Coastguard Workertesting "bracket expansion" \
222*cf5a6c84SAndroid Build Coastguard Worker  "echo {A{a,b}B{c,d}C}" "{AaBcC} {AaBdC} {AbBcC} {AbBdC}\n" "" ""
223*cf5a6c84SAndroid Build Coastguard Workertesting "brackets2" "echo {A{a,b}B{c,d}C,D}" "AaBcC AaBdC AbBcC AbBdC D\n" "" ""
224*cf5a6c84SAndroid Build Coastguard Workertesting "brackets3" 'echo {A"b,c"D}' "{Ab,cD}\n" "" ""
225*cf5a6c84SAndroid Build Coastguard Workertesting "brackets4" 'echo {A"bc",D}' "Abc D\n" "" ""
226*cf5a6c84SAndroid Build Coastguard Workertesting "brackets5" 'echo {A,B,C' "{A,B,C\n" "" ""
227*cf5a6c84SAndroid Build Coastguard Workertesting "brackets6" 'echo {{{{A,B},C}D},E}' "{AD} {BD} {CD} E\n" "" ""
228*cf5a6c84SAndroid Build Coastguard Workertesting "brackets7" 'echo {{{a,b},c,{d,e}},f}' "a b c d e f\n" "" ""
229*cf5a6c84SAndroid Build Coastguard Workertesting "brackets8" 'echo A{a{b,c{B,C}D}d{e,f},g{h,i}j}E' \
230*cf5a6c84SAndroid Build Coastguard Worker  "AabdeE AabdfE AacBDdeE AacBDdfE AacCDdeE AacCDdfE AghjE AgijE\n" "" ""
231*cf5a6c84SAndroid Build Coastguard Workertesting "brackets9" 'echo A{B{C,D}E{N,O},F{G,H}I}J{K,L}M' \
232*cf5a6c84SAndroid Build Coastguard Worker  "ABCENJKM ABCENJLM ABCEOJKM ABCEOJLM ABDENJKM ABDENJLM ABDEOJKM ABDEOJLM AFGIJKM AFGIJLM AFHIJKM AFHIJLM\n" "" ""
233*cf5a6c84SAndroid Build Coastguard Workerfor i in /root /var/root /; do [ -e $i ] && EXPECT=$i && break; done
234*cf5a6c84SAndroid Build Coastguard Workertesting "bracket+tilde" "echo {~,~root}/pwd" "$HOME/pwd $EXPECT/pwd\n" "" ""
235*cf5a6c84SAndroid Build Coastguard Worker
236*cf5a6c84SAndroid Build Coastguard Worker# Slices
237*cf5a6c84SAndroid Build Coastguard Worker
238*cf5a6c84SAndroid Build Coastguard Workertesting '${x#prefix}' 'x=abcde; echo ${x#abc}' 'de\n' '' ''
239*cf5a6c84SAndroid Build Coastguard Workertesting '${x#short} ${x##long}' 'x=banana; echo ${x#b*n} ${x##b*n}' \
240*cf5a6c84SAndroid Build Coastguard Worker  'ana a\n' '' ''
241*cf5a6c84SAndroid Build Coastguard Workertoyonly testing '${x#utf8}' 'x=aそcde; echo ${x##a?c}' 'de\n' '' ''
242*cf5a6c84SAndroid Build Coastguard Workertesting '${x%y}' 'x=potato; echo ${x%t*o} ${x%%t*o}' 'pota po\n' '' ''
243*cf5a6c84SAndroid Build Coastguard Workertesting 'x=${x%y}' 'x=potato; x=${x%t*o}; echo $x' 'pota\n' '' ''
244*cf5a6c84SAndroid Build Coastguard Workertesting '${x%glob}' 'x=abc-def; echo ${x%-*f} ${x-*c}' 'abc abc-def\n' '' ''
245*cf5a6c84SAndroid Build Coastguard Workertesting 'x=${x//y}' 'x=potato; x=${x//ta}; echo $x' 'poto\n' '' ''
246*cf5a6c84SAndroid Build Coastguard Workertesting '${x^y}' 'x=aaaaa; echo ${x^a}' 'Aaaaa\n' '' ''
247*cf5a6c84SAndroid Build Coastguard Workertesting '${x^^y}' 'x=abccdec; echo ${x^^c}; x=abcdec; echo ${x^^c}' \
248*cf5a6c84SAndroid Build Coastguard Worker  'abCCdeC\nabCdeC\n' '' ''
249*cf5a6c84SAndroid Build Coastguard Workertesting '${x,y}' 'x=BBB; echo ${x,B}' 'bBB\n' '' ''
250*cf5a6c84SAndroid Build Coastguard Workertesting '${x,,y}' 'x=POTATO; echo ${x,,} ${x,,?} ${x,,*} ${x,,T}' \
251*cf5a6c84SAndroid Build Coastguard Worker  'potato potato potato POtAtO\n' '' ''
252*cf5a6c84SAndroid Build Coastguard Worker
253*cf5a6c84SAndroid Build Coastguard Workermkdir -p abc/def/ghi
254*cf5a6c84SAndroid Build Coastguard Workertouch www
255*cf5a6c84SAndroid Build Coastguard Workertesting 'wildcards' 'echo w[v-x]w w[x-v]w abc/*/ghi' \
256*cf5a6c84SAndroid Build Coastguard Worker  'www w[x-v]w abc/def/ghi\n' '' ''
257*cf5a6c84SAndroid Build Coastguard Workertesting 'hidden wildcards' \
258*cf5a6c84SAndroid Build Coastguard Worker  'touch .abc abc && echo *bc && echo and && echo .*bc' \
259*cf5a6c84SAndroid Build Coastguard Worker  'abc\nand\n.abc\n' '' ''
260*cf5a6c84SAndroid Build Coastguard Worker
261*cf5a6c84SAndroid Build Coastguard Workertesting "backtick1" 'x=fred; echo `echo $x`' 'fred\n' "" ""
262*cf5a6c84SAndroid Build Coastguard Workertesting "backtick2" 'x=fred; echo `x=y; echo $x`; echo $x' 'y\nfred\n' "" ""
263*cf5a6c84SAndroid Build Coastguard Workertesting '$(( ) )' 'echo ab$((echo hello) | tr e x)cd' "abhxllocd\n" "" ""
264*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing '$((x=y)) lifetime' 'a=boing; echo $a $a$((a=4))$a $a' 'boing boing44 4\n' '' ''
265*cf5a6c84SAndroid Build Coastguard Worker
266*cf5a6c84SAndroid Build Coastguard Workertesting 'quote' "echo \"'\"" "'\n" "" ""
267*cf5a6c84SAndroid Build Coastguard Worker
268*cf5a6c84SAndroid Build Coastguard Workertesting "math" 'echo $((1+2))' '3\n' '' ''
269*cf5a6c84SAndroid Build Coastguard Workertesting "[oldmath]" 'echo $[1+2]' '3\n' '' ''
270*cf5a6c84SAndroid Build Coastguard Workertesting "math basic priority" 'echo $((1+2*3**4))' '163\n' '' ''
271*cf5a6c84SAndroid Build Coastguard Workertesting "math paren" 'echo $(((1+2)*3))' '9\n' '' ''
272*cf5a6c84SAndroid Build Coastguard Workertesting "math spaces" 'echo $(( ( 1 + 2 ) * 7 - 5 ** 2 ))' '-4\n' '' ''
273*cf5a6c84SAndroid Build Coastguard Workertesting "((<)) isn't redirect" '((1<2)) </dev/null && echo yes' 'yes\n' '' ''
274*cf5a6c84SAndroid Build Coastguard Workertesting "((>)) isn't redirect" '((1>2)) </dev/null || echo yes' 'yes\n' '' ''
275*cf5a6c84SAndroid Build Coastguard Workertesting "((not math) )" '((echo hello) )' 'hello\n' '' ''
276*cf5a6c84SAndroid Build Coastguard Workertesting "preincrement" 'echo $((++x)); echo $x' '1\n1\n' '' ''
277*cf5a6c84SAndroid Build Coastguard Workertesting "preincrement vs prefix plus" 'echo $((+++x)); echo $x' '1\n1\n' '' ''
278*cf5a6c84SAndroid Build Coastguard Workertesting "predecrement" 'echo $((--x)); echo $x' '-1\n-1\n' '' ''
279*cf5a6c84SAndroid Build Coastguard Workertesting "predecrement vs prefix minus" 'echo $((---x)); echo $x' '1\n-1\n' '' ''
280*cf5a6c84SAndroid Build Coastguard Workertesting "minus-minus-minus" 'echo $((x---7)); echo $x' '-7\n-1\n' '' ''
281*cf5a6c84SAndroid Build Coastguard Workertesting "x---y is x-- -y not x- --y" 'x=1 y=1; echo $((x---y)) $x $y' '0 0 1\n'\
282*cf5a6c84SAndroid Build Coastguard Worker  '' ''
283*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing "nesting ? :" \
284*cf5a6c84SAndroid Build Coastguard Worker  'for((i=0;i<8;i++)); do echo $((i&1?i&2?1:i&4?2:3:4));done' \
285*cf5a6c84SAndroid Build Coastguard Worker  '4\n3\n4\n1\n4\n2\n4\n1\n' '' ''
286*cf5a6c84SAndroid Build Coastguard Workertesting "inherited assignment suppression" 'echo $((0 ? (x++) : 2)); echo $x' \
287*cf5a6c84SAndroid Build Coastguard Worker  "2\n\n" "" ""
288*cf5a6c84SAndroid Build Coastguard Workertesting "boolean vs logical" 'echo $((2|4&&8))' '1\n' '' ''
289*cf5a6c84SAndroid Build Coastguard Workertesting "&& vs || priority" \
290*cf5a6c84SAndroid Build Coastguard Worker  'echo $((w++||x++&&y++||z++)) w=$w x=$x y=$y z=$z' \
291*cf5a6c84SAndroid Build Coastguard Worker  '0 w=1 x=1 y= z=1\n' '' ''
292*cf5a6c84SAndroid Build Coastguard Workertesting "|| vs && priority" \
293*cf5a6c84SAndroid Build Coastguard Worker  'echo $((w++&&x++||y++&&z++)) w=$w x=$x y=$y z=$z' \
294*cf5a6c84SAndroid Build Coastguard Worker  '0 w=1 x= y=1 z=\n' '' ''
295*cf5a6c84SAndroid Build Coastguard Worker$BROKEN shxpect '/0' I$'echo $((1/0)); echo here\n' E E"$P" I$'echo $?\n' O$'1\n'
296*cf5a6c84SAndroid Build Coastguard Worker$BROKEN shxpect '%0' I$'echo $((1%0)); echo here\n' E E"$P" I$'echo $?\n' O$'1\n'
297*cf5a6c84SAndroid Build Coastguard Worker$BROKEN shxpect '/=0' I$'echo $((x/=0)); echo here\n' E E"$P" I$'echo $?\n' O$'1\n'
298*cf5a6c84SAndroid Build Coastguard Worker$BROKEN shxpect '%=0' I$'echo $((x%=0)); echo here\n' E E"$P" I$'echo $?\n' O$'1\n'
299*cf5a6c84SAndroid Build Coastguard Worker
300*cf5a6c84SAndroid Build Coastguard Worker# Loops and flow control
301*cf5a6c84SAndroid Build Coastguard Workertesting "case" 'for i in A C J B; do case "$i" in A) echo got A ;; B) echo and B ;; C) echo then C ;; *) echo default ;; esac; done' \
302*cf5a6c84SAndroid Build Coastguard Worker  "got A\nthen C\ndefault\nand B\n" "" ""
303*cf5a6c84SAndroid Build Coastguard Workertesting 'case;;&' 'case wow in w?w) echo ok;;& wow) echo no; esac' 'ok\nno\n' \
304*cf5a6c84SAndroid Build Coastguard Worker  "" ""
305*cf5a6c84SAndroid Build Coastguard Workertesting "case newlines" \
306*cf5a6c84SAndroid Build Coastguard Worker  $'case i\n\nin\n\na) echo one\n\n;;\n\ni)\n\necho two\n\n;;\n\nesac' \
307*cf5a6c84SAndroid Build Coastguard Worker  "two\n" "" ""
308*cf5a6c84SAndroid Build Coastguard Workertesting "case block" \
309*cf5a6c84SAndroid Build Coastguard Worker  $'case X in\n  X) printf %s "X" || { echo potato;} ;;\nesac' 'X' '' ''
310*cf5a6c84SAndroid Build Coastguard Workertesting 'loop in && ||' \
311*cf5a6c84SAndroid Build Coastguard Worker  'false && for i in a b c; do echo $i; done || echo no' 'no\n' '' ''
312*cf5a6c84SAndroid Build Coastguard Workertesting "continue" 'for i in a b c; do for j in d e f; do echo $i $j; continue 2; done; done' \
313*cf5a6c84SAndroid Build Coastguard Worker  "a d\nb d\nc d\n" "" ""
314*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing "piped loops that don't exit" \
315*cf5a6c84SAndroid Build Coastguard Worker  'while X=$(($X+1)); do echo $X; done | while read i; do echo $i; done | head -n 5' \
316*cf5a6c84SAndroid Build Coastguard Worker  '1\n2\n3\n4\n5\n' '' ''
317*cf5a6c84SAndroid Build Coastguard Worker
318*cf5a6c84SAndroid Build Coastguard Worker# <glinda>A variable occurred</glinda>
319*cf5a6c84SAndroid Build Coastguard Worker
320*cf5a6c84SAndroid Build Coastguard Workertesting "expand" 'echo $PWD' "$(pwd)\n" "" ""
321*cf5a6c84SAndroid Build Coastguard Workertesting "expand2" 'echo "$PWD"' "$(pwd)\n" "" ""
322*cf5a6c84SAndroid Build Coastguard Workertesting "expand3" 'echo "$"PWD' '$PWD\n' "" ""
323*cf5a6c84SAndroid Build Coastguard Workertesting "expand4" 'P=x; echo "$P"WD' 'xWD\n' "" ""
324*cf5a6c84SAndroid Build Coastguard Workertesting "dequote" "echo one 'two' ''three 'fo'ur '\\'" \
325*cf5a6c84SAndroid Build Coastguard Worker  'one two three four \\\n' '' ''
326*cf5a6c84SAndroid Build Coastguard Worker
327*cf5a6c84SAndroid Build Coastguard Workertesting "leading variable assignment" 'abc=def env | grep ^abc=; echo $abc' \
328*cf5a6c84SAndroid Build Coastguard Worker  "abc=def\n\n" "" ""
329*cf5a6c84SAndroid Build Coastguard Workertesting "leading variable assignments" \
330*cf5a6c84SAndroid Build Coastguard Worker  "abc=def ghi=jkl env | egrep '^(abc|ghi)=' | sort; echo \$abc \$ghi" \
331*cf5a6c84SAndroid Build Coastguard Worker  "abc=def\nghi=jkl\n\n" "" ""
332*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing "leading assignment occurs after parsing" \
333*cf5a6c84SAndroid Build Coastguard Worker  'abc=def; abc=ghi echo $abc' "def\n" "" ""
334*cf5a6c84SAndroid Build Coastguard Workertesting "leading assignment space" 'X="abc  def"; Y=$X; echo "$Y"' \
335*cf5a6c84SAndroid Build Coastguard Worker  "abc  def\n" "" ""
336*cf5a6c84SAndroid Build Coastguard Workertesting "leading assignment space2" \
337*cf5a6c84SAndroid Build Coastguard Worker  'chicken() { X="$@"; }; chicken a b c d e; echo "$X"' 'a b c d e\n' '' ''
338*cf5a6c84SAndroid Build Coastguard Workertesting "leading assignment fail2" \
339*cf5a6c84SAndroid Build Coastguard Worker  "{ 1blah=123 echo hello;} 2>/dev/null || echo no" "no\n" "" ""
340*cf5a6c84SAndroid Build Coastguard Workertesting "leading assignment redirect" \
341*cf5a6c84SAndroid Build Coastguard Worker  "blah=123 echo hello > walrus && ls walrus" "walrus\n" "" ""
342*cf5a6c84SAndroid Build Coastguard Workerrm -f walrus
343*cf5a6c84SAndroid Build Coastguard Worker
344*cf5a6c84SAndroid Build Coastguard Workertesting "{1..5}" "echo {1..5}" "1 2 3 4 5\n" "" ""
345*cf5a6c84SAndroid Build Coastguard Workertesting "{5..1}" "echo {5..1}" "5 4 3 2 1\n" "" ""
346*cf5a6c84SAndroid Build Coastguard Workertesting "{5..1..2}" "echo {5..1..2}" "5 3 1\n" "" ""
347*cf5a6c84SAndroid Build Coastguard Workertesting "{a..z..-3}" "echo {a..z..-3}" "a d g j m p s v y\n" "" ""
348*cf5a6c84SAndroid Build Coastguard Worker
349*cf5a6c84SAndroid Build Coastguard Workermkfifo POIT
350*cf5a6c84SAndroid Build Coastguard Workertesting 'background curly block' \
351*cf5a6c84SAndroid Build Coastguard Worker  '{ sed s/ll/xx/ POIT; }& echo hello > POIT; wait && echo yes' \
352*cf5a6c84SAndroid Build Coastguard Worker  'hexxo\nyes\n' '' ''
353*cf5a6c84SAndroid Build Coastguard Workerrm -f POIT
354*cf5a6c84SAndroid Build Coastguard Worker
355*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing 'background pipe block' \
356*cf5a6c84SAndroid Build Coastguard Worker  'if true; then { sleep .25;bzcat "$FILES"/blkid/ntfs.bz2; }& fi | wc -c' \
357*cf5a6c84SAndroid Build Coastguard Worker  '8388608\n' '' ''
358*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing 'background variable assignment' 'X=x; X=y & echo $X' 'x\n' '' ''
359*cf5a6c84SAndroid Build Coastguard Worker
360*cf5a6c84SAndroid Build Coastguard Worker#$ IFS=x X=xyxz; for i in abc${X}def; do echo =$i=; done
361*cf5a6c84SAndroid Build Coastguard Worker#=abc=
362*cf5a6c84SAndroid Build Coastguard Worker#=y=
363*cf5a6c84SAndroid Build Coastguard Worker#=zdef=
364*cf5a6c84SAndroid Build Coastguard Worker
365*cf5a6c84SAndroid Build Coastguard Workertesting "IFS whitespace before/after" \
366*cf5a6c84SAndroid Build Coastguard Worker  'IFS=" x"; A=" x " B=" x" C="x " D=x E="   "; for i in $A $B $C $D L$A L$B L$C L$D $A= $B= $C= $D= L$A= L$B= L$C= L$D=; do echo -n {$i}; done' \
367*cf5a6c84SAndroid Build Coastguard Worker  "{}{}{}{}{L}{L}{L}{L}{}{=}{}{=}{}{=}{}{=}{L}{=}{L}{=}{L}{=}{L}{=}" "" ""
368*cf5a6c84SAndroid Build Coastguard Workertesting "quotes and whitespace" \
369*cf5a6c84SAndroid Build Coastguard Worker  'A="   abc   def   "; for i in ""$A""; do echo =$i=; done' \
370*cf5a6c84SAndroid Build Coastguard Worker  "==\n=abc=\n=def=\n==\n" "" ""
371*cf5a6c84SAndroid Build Coastguard Workertesting "quotes and whitespace2" \
372*cf5a6c84SAndroid Build Coastguard Worker  'A="   abc   def   "; for i in """"$A""; do echo =$i=; done' \
373*cf5a6c84SAndroid Build Coastguard Worker  "==\n=abc=\n=def=\n==\n" "" ""
374*cf5a6c84SAndroid Build Coastguard Workertesting "quotes and whitespace3" \
375*cf5a6c84SAndroid Build Coastguard Worker  'A="   abc   def   "; for i in ""x""$A""; do echo =$i=; done' \
376*cf5a6c84SAndroid Build Coastguard Worker  "=x=\n=abc=\n=def=\n==\n" "" ""
377*cf5a6c84SAndroid Build Coastguard Worker
378*cf5a6c84SAndroid Build Coastguard Workertesting "IFS" 'IFS=x; A=abx; echo -n "$A"' "abx" "" ""
379*cf5a6c84SAndroid Build Coastguard Workertesting "IFS2" 'IFS=x; A=abx; echo -n $A' "ab" "" ""
380*cf5a6c84SAndroid Build Coastguard Workertesting "IFS3" 'IFS=x; echo "$(echo abx)"' "abx\n" "" ""
381*cf5a6c84SAndroid Build Coastguard Workertesting "IFS4" 'IFS=x; echo $(echo abx)y' "ab y\n" "" ""
382*cf5a6c84SAndroid Build Coastguard Workertesting "IFS5" 'IFS=xy; for i in abcxdefyghi; do echo =$i=; done' \
383*cf5a6c84SAndroid Build Coastguard Worker  "=abc def ghi=\n" "" ""
384*cf5a6c84SAndroid Build Coastguard Workertesting "curly bracket whitespace" 'for i in {$,} ""{$,}; do echo ="$i"=; done'\
385*cf5a6c84SAndroid Build Coastguard Worker  '=$=\n=$=\n==\n' '' ''
386*cf5a6c84SAndroid Build Coastguard Worker
387*cf5a6c84SAndroid Build Coastguard Workertesting 'empty $! is blank' 'echo $!' "\n" "" ""
388*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing '$! = jobs -p' 'true & [ $(jobs -p) = $! ] && echo yes' "yes\n" "" ""
389*cf5a6c84SAndroid Build Coastguard Worker
390*cf5a6c84SAndroid Build Coastguard Workertesting '$*' 'cc(){ for i in $*;do echo =$i=;done;};cc "" "" "" "" ""' \
391*cf5a6c84SAndroid Build Coastguard Worker  "" "" ""
392*cf5a6c84SAndroid Build Coastguard Workertesting '$*2' 'cc(){ for i in "$*";do echo =$i=;done;};cc ""' \
393*cf5a6c84SAndroid Build Coastguard Worker  "==\n" "" ""
394*cf5a6c84SAndroid Build Coastguard Workertesting '$*3... Flame. Flames. Flames, on the side of my face...' \
395*cf5a6c84SAndroid Build Coastguard Worker  'cc(){ for i in "$*";do echo =$i=;done;};cc "" ""' "= =\n" "" ""
396*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing 'why... oh.' \
397*cf5a6c84SAndroid Build Coastguard Worker  'cc() { echo ="$*"=; for i in =$*=; do echo -$i-; done;}; cc "" ""; echo and; cc ""' \
398*cf5a6c84SAndroid Build Coastguard Worker  '= =\n-=-\n-=-\nand\n==\n-==-\n' "" ""
399*cf5a6c84SAndroid Build Coastguard Workertesting 'really?' 'cc() { for i in $*; do echo -$i-; done;}; cc "" "" ""' \
400*cf5a6c84SAndroid Build Coastguard Worker  "" "" ""
401*cf5a6c84SAndroid Build Coastguard Workertesting 'Sigh.' 'cc() { echo =$1$2=;}; cc "" ""' "==\n" "" ""
402*cf5a6c84SAndroid Build Coastguard Workertesting '$*4' 'cc(){ for i in "$*";do echo =$i=;done;};cc "" "" "" "" ""' \
403*cf5a6c84SAndroid Build Coastguard Worker  "= =\n" "" ""
404*cf5a6c84SAndroid Build Coastguard Workertesting '$*5' 'cc(){ for i in "$*";do echo =$i=;done;};cc "" "abc" ""' \
405*cf5a6c84SAndroid Build Coastguard Worker  "= abc =\n" "" ""
406*cf5a6c84SAndroid Build Coastguard Worker
407*cf5a6c84SAndroid Build Coastguard Worker# creating empty arguments without quotes
408*cf5a6c84SAndroid Build Coastguard Workertesting '$* + IFS' \
409*cf5a6c84SAndroid Build Coastguard Worker  'IFS=x; cc(){ for i in $*; do echo =$i=;done;};cc xabcxx' \
410*cf5a6c84SAndroid Build Coastguard Worker  "==\n=abc=\n==\n" "" ""
411*cf5a6c84SAndroid Build Coastguard Workertesting '$@' 'cc(){ for i in "$@";do echo =$i=;done;};cc "" "" "" "" ""' \
412*cf5a6c84SAndroid Build Coastguard Worker  "==\n==\n==\n==\n==\n" "" ""
413*cf5a6c84SAndroid Build Coastguard Workertesting "IFS10" 'IFS=bcd; A=abcde; for i in $A; do echo =$i=; done' \
414*cf5a6c84SAndroid Build Coastguard Worker  "=a=\n==\n==\n=e=\n" "" ""
415*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing "IFS11" \
416*cf5a6c84SAndroid Build Coastguard Worker  'IFS=x; chicken() { for i in $@$@; do echo =$i=; done;}; chicken one "" abc dxf ghi' \
417*cf5a6c84SAndroid Build Coastguard Worker  "=one=\n==\n=abc=\n=d=\n=f=\n=ghione=\n==\n=abc=\n=d=\n=f=\n=ghi=\n" "" ""
418*cf5a6c84SAndroid Build Coastguard Workertesting "IFS12" 'IFS=3;chicken(){ return 3;}; chicken;echo 3$?3' '3 3\n' "" ""
419*cf5a6c84SAndroid Build Coastguard Worker
420*cf5a6c84SAndroid Build Coastguard Workertesting "IFS combinations" \
421*cf5a6c84SAndroid Build Coastguard Worker  'IFS=" x"; A=" x " B=" x" C="x " D=x E="   "; for i in $A $B $C $D L$A L$B L$C L$D $A= $B= $C= $D= L$A= L$B= L$C= L$D=; do echo -n {$i}; done' \
422*cf5a6c84SAndroid Build Coastguard Worker  "{}{}{}{}{L}{L}{L}{L}{}{=}{}{=}{}{=}{}{=}{L}{=}{L}{=}{L}{=}{L}{=}" "" ""
423*cf5a6c84SAndroid Build Coastguard Worker
424*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing "! isn't special" "echo !" "!\n" "" ""
425*cf5a6c84SAndroid Build Coastguard Workertesting "! by itself" '!; echo $?' "1\n" "" ""
426*cf5a6c84SAndroid Build Coastguard Workertesting "! true" '! true; echo $?' "1\n" "" ""
427*cf5a6c84SAndroid Build Coastguard Workertesting "! ! true" '! ! true; echo $?' "0\n" "" ""
428*cf5a6c84SAndroid Build Coastguard Workertesting "! syntax err" '! echo 2>/dev/null < doesnotexist; echo $?' "0\n" "" ""
429*cf5a6c84SAndroid Build Coastguard Worker
430*cf5a6c84SAndroid Build Coastguard Worker# The bash man page doesn't say quote removal here, and yet:
431*cf5a6c84SAndroid Build Coastguard Workertesting "case quoting" 'case a in "a") echo hello;; esac' 'hello\n' "" ""
432*cf5a6c84SAndroid Build Coastguard Worker
433*cf5a6c84SAndroid Build Coastguard Workertesting "subshell splitting" 'for i in $(true); do echo =$i=; done' "" "" ""
434*cf5a6c84SAndroid Build Coastguard Workertesting "subshell split 2" 'for i in $(echo "one two thr"); do echo =$i=; done'\
435*cf5a6c84SAndroid Build Coastguard Worker  "=one=\n=two=\n=thr=\n" "" ""
436*cf5a6c84SAndroid Build Coastguard Worker
437*cf5a6c84SAndroid Build Coastguard Worker# variable assignment argument splitting only performed for "$@"
438*cf5a6c84SAndroid Build Coastguard Workertesting "assignment nosplit" 'X="one two"; Y=$X; echo $Y' "one two\n" "" ""
439*cf5a6c84SAndroid Build Coastguard Workertesting "argument splitting" \
440*cf5a6c84SAndroid Build Coastguard Worker  'chicken() { for i in a"$@"b;do echo =$i=;done;}; chicken 123 456 789' \
441*cf5a6c84SAndroid Build Coastguard Worker  "=a123=\n=456=\n=789b=\n" "" ""
442*cf5a6c84SAndroid Build Coastguard Workertesting "assignment nosplit2" 'pop(){ X="$@";};pop one two three; echo $X' \
443*cf5a6c84SAndroid Build Coastguard Worker  "one two three\n" "" ""
444*cf5a6c84SAndroid Build Coastguard Worker
445*cf5a6c84SAndroid Build Coastguard Worker#testing "leading assignments don't affect current line" \
446*cf5a6c84SAndroid Build Coastguard Worker#  'VAR=12345 echo ${VAR}a' "a\n" "" ""
447*cf5a6c84SAndroid Build Coastguard Worker#testing "can't have space before first : but yes around arguments" \
448*cf5a6c84SAndroid Build Coastguard Worker#  'BLAH=abcdefghi; echo ${BLAH: 1 : 3 }' "bcd\n" "" ""
449*cf5a6c84SAndroid Build Coastguard Worker
450*cf5a6c84SAndroid Build Coastguard Workertesting "subshell exit err" '(exit 42); echo $?' "42\n" "" ""
451*cf5a6c84SAndroid Build Coastguard Worker
452*cf5a6c84SAndroid Build Coastguard Worker# Same thing twice, but how do we cmp if exec exited?
453*cf5a6c84SAndroid Build Coastguard Worker#testing 'exec and $$' testing 'echo $$;exec readlink /proc/self' 
454*cf5a6c84SAndroid Build Coastguard Worker
455*cf5a6c84SAndroid Build Coastguard WorkerX="$(realpath $(which readlink))"
456*cf5a6c84SAndroid Build Coastguard Workertesting "exec in paren" \
457*cf5a6c84SAndroid Build Coastguard Worker  '(exec readlink /proc/self/exe);echo hello' "$X\nhello\n" "" ""
458*cf5a6c84SAndroid Build Coastguard Workertesting "exec in brackets" \
459*cf5a6c84SAndroid Build Coastguard Worker  "{ exec readlink /proc/self/exe;};echo hi" "$X\n" "" ""
460*cf5a6c84SAndroid Build Coastguard Worker
461*cf5a6c84SAndroid Build Coastguard WorkerNOSPACE=1 testing "curly brackets and pipe" \
462*cf5a6c84SAndroid Build Coastguard Worker  '{ echo one; echo two ; } | tee blah.txt; wc blah.txt' \
463*cf5a6c84SAndroid Build Coastguard Worker  "one\ntwo\n2 2 8 blah.txt\n" "" ""
464*cf5a6c84SAndroid Build Coastguard WorkerNOSPACE=1 testing "parentheses and pipe" \
465*cf5a6c84SAndroid Build Coastguard Worker  '(echo two;echo three)|tee blah.txt;wc blah.txt' \
466*cf5a6c84SAndroid Build Coastguard Worker  "two\nthree\n2 2 10 blah.txt\n" "" ""
467*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing "pipe into parentheses" \
468*cf5a6c84SAndroid Build Coastguard Worker  'echo hello | (read i <input; echo $i; read i; echo $i)' \
469*cf5a6c84SAndroid Build Coastguard Worker  "there\nhello\n" "there\n" ""
470*cf5a6c84SAndroid Build Coastguard Worker
471*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing "\$''" $'echo $\'abc\\\'def\\nghi\'' "abc'def\nghi\n" '' ''
472*cf5a6c84SAndroid Build Coastguard Workertesting "shift shift" 'shift; shift; shift; echo $? hello' "1 hello\n" "" ""
473*cf5a6c84SAndroid Build Coastguard Workertesting 'search cross $*' 'chicken() { echo ${*/b c/ghi}; }; chicken a b c d' \
474*cf5a6c84SAndroid Build Coastguard Worker  "a b c d\n" "" ""
475*cf5a6c84SAndroid Build Coastguard Workertesting 'eval $IFS' 'IFS=x; X=x; eval abc=a${X}b 2>/dev/null; echo $abc' \
476*cf5a6c84SAndroid Build Coastguard Worker  "\n" '' ''
477*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing '${@:3:5}' 'chicken() { for i in "${@:3:5}"; do echo =$i=; done; } ; chicken ab cd ef gh ij kl mn op qr' \
478*cf5a6c84SAndroid Build Coastguard Worker  '=ef=\n=gh=\n=ij=\n=kl=\n=mn=\n' '' ''
479*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing '${*:3:5}' 'chicken() { for i in "${*:3:5}"; do unset IFS; echo =$i=; done; } ; IFS=x chicken ab cd ef gh ij kl mn op qr' \
480*cf5a6c84SAndroid Build Coastguard Worker  '=efxghxijxklxmn=\n' '' ''
481*cf5a6c84SAndroid Build Coastguard Workertesting 'sequence check' 'IFS=x; X=abxcd; echo ${X/bxc/g}' 'agd\n' '' ''
482*cf5a6c84SAndroid Build Coastguard Worker
483*cf5a6c84SAndroid Build Coastguard Worker# TODO: The txpect plumbing does not work right yet even on TEST_HOST
484*cf5a6c84SAndroid Build Coastguard Worker#txpect "backtick0" "$SS" "E$P" 'IX=fred; echo `echo \\\\$x`'$'\n' 'Ofred' "E$P" X0
485*cf5a6c84SAndroid Build Coastguard Worker#txpect "backtick1" "$SS" "E$P" 'IX=fred; echo `echo $x`'$'\n' 'Ofred'$'\n' "E$P" X0
486*cf5a6c84SAndroid Build Coastguard Worker#txpect "backtick2" "$SS" "E$P" 'IX=fred; echo `x=y; echo $x`' $'Oy\n' "E$P" X0
487*cf5a6c84SAndroid Build Coastguard Worker
488*cf5a6c84SAndroid Build Coastguard Workershxpect '${ with newline' I$'HELLO=abc; echo ${HELLO/b/\n' E"> " I$'}\n' O$'a c\n'
489*cf5a6c84SAndroid Build Coastguard Worker
490*cf5a6c84SAndroid Build Coastguard Workertesting 'here0' 'cat<<<hello' 'hello\n' '' ''
491*cf5a6c84SAndroid Build Coastguard Workershxpect 'here1' I$'POTATO=123; cat << EOF\n' E"> " \
492*cf5a6c84SAndroid Build Coastguard Worker  I$'$POTATO\n' E"> " I$'EOF\n' O$'123\n'
493*cf5a6c84SAndroid Build Coastguard Workershxpect 'here2' I$'POTATO=123; cat << E"O"F\n' E"> " \
494*cf5a6c84SAndroid Build Coastguard Worker  I$'$POTATO\n' E"> " I$'EOF\n' O$'$POTATO\n'
495*cf5a6c84SAndroid Build Coastguard Workertesting 'here3' 'abc(){ cat <<< x"$@"yz;};abc one two "three  four"' \
496*cf5a6c84SAndroid Build Coastguard Worker  "xone two three  fouryz\n" "" ""
497*cf5a6c84SAndroid Build Coastguard Workertesting 'here4' 'for i in one two three; do cat <<< "ab${i}de"; done' \
498*cf5a6c84SAndroid Build Coastguard Worker  'abonede\nabtwode\nabthreede\n' '' ''
499*cf5a6c84SAndroid Build Coastguard Workertesting 'here5' $'cat << EOF && cat << EOF2\nEOF2\nEOF\nEOF\nEOF2' \
500*cf5a6c84SAndroid Build Coastguard Worker  'EOF2\nEOF\n' '' ''
501*cf5a6c84SAndroid Build Coastguard Worker# Nothing is actually quoted, but there are quotes, therefore...
502*cf5a6c84SAndroid Build Coastguard Workertesting 'here6' $'cat << EOF""\n$POTATO\nEOF' '$POTATO\n' '' ''
503*cf5a6c84SAndroid Build Coastguard Worker# Not ambiguous when split, unlike <$FILENAME redirects
504*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing 'here7' 'ABC="abc def"; cat <<< $ABC' 'abc def\n' '' ''
505*cf5a6c84SAndroid Build Coastguard Worker# What does HERE expansion _not_ expand?
506*cf5a6c84SAndroid Build Coastguard Workertesting 'here8' $'ABC="x y"\ncat << EOF\n~root/{"$ABC",def}\nEOF' \
507*cf5a6c84SAndroid Build Coastguard Worker  '~root/{"x y",def}\n' '' ''
508*cf5a6c84SAndroid Build Coastguard Workertesting '<<- eats leading tabs before expansion, but not after' \
509*cf5a6c84SAndroid Build Coastguard Worker  $'A=$\'\\tone\'; cat <<- EOF\n\t\t$A\n\ttwo\nEOF' "\tone\ntwo\n" '' ''
510*cf5a6c84SAndroid Build Coastguard Worker
511*cf5a6c84SAndroid Build Coastguard Workertesting '${var}' 'X=abcdef; echo ${X}' 'abcdef\n' '' '' 
512*cf5a6c84SAndroid Build Coastguard Workertesting '${#}' 'X=abcdef; echo ${#X}' "6\n" "" ""
513*cf5a6c84SAndroid Build Coastguard Workertesting 'empty ${}' '{ echo ${};} 2>&1 | grep -o bad' 'bad\n' '' ''
514*cf5a6c84SAndroid Build Coastguard Worker$BROKEN shxpect 'empty ${} syntax err abort' I$'echo ${}; echo hello\n' \
515*cf5a6c84SAndroid Build Coastguard Worker  E I$'echo and\n' O$'and\n'
516*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing '${$b}' '{ echo ${$b};} 2>&1 | grep -o bad' 'bad\n' '' ''
517*cf5a6c84SAndroid Build Coastguard Workertesting '${!PATH*}' 'echo ${!PATH*}' 'PATH\n' '' ''
518*cf5a6c84SAndroid Build Coastguard Workertesting '${!PATH@}' 'echo ${!PATH@}' 'PATH\n' '' ''
519*cf5a6c84SAndroid Build Coastguard Worker#testing '${!PATH[@]}' 'echo ${!PATH[@]}' '0\n' '' ''
520*cf5a6c84SAndroid Build Coastguard Workertesting '${!x}' 'X=abcdef Y=X; echo ${!Y}' 'abcdef\n' '' ''
521*cf5a6c84SAndroid Build Coastguard Workertesting '${!x@}' 'ABC=def; def=ghi; echo ${!ABC@}' 'ABC\n' '' ''
522*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing '${!x} err' '{ X=abcdef Y=X:2; echo ${!Y}; echo bang;} 2>/dev/null' \
523*cf5a6c84SAndroid Build Coastguard Worker  '' '' ''
524*cf5a6c84SAndroid Build Coastguard Workertesting '${!x*}' 'abcdef=1 abc=2 abcq=; echo "${!abc@}" | tr " " \\n | sort' \
525*cf5a6c84SAndroid Build Coastguard Worker  'abc\nabcdef\nabcq\n' '' ''
526*cf5a6c84SAndroid Build Coastguard Workertesting '${!x*} none' 'echo "${!abc*}"' '\n' '' ''
527*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing '${!x*} err' '{ echo "${!abc*x}"; echo boing;} 2>/dev/null' '' '' ''
528*cf5a6c84SAndroid Build Coastguard Worker# TODO bash 5.x broke this
529*cf5a6c84SAndroid Build Coastguard Worker#testing '${!none@Q}' 'echo ${X@Q} ${!X@Q}; X=ABC; echo ${!X@Q}' '\n\n' '' ''
530*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing '${!x@Q}' 'ABC=123 X=ABC; echo ${!X@Q}' "'123'\n" '' ''
531*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing '${#@Q}' 'echo ${#@Q}' "'0'\n" '' ''
532*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing '${!*}' 'xx() { echo ${!*};}; fruit=123; xx fruit' '123\n' '' ''
533*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing '${!*} indirect' 'xx() { echo ${!a@Q};}; a=@; xx one two three' \
534*cf5a6c84SAndroid Build Coastguard Worker  "'one' 'two' 'three'\n" '' ''
535*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing '${!x@ } match' \
536*cf5a6c84SAndroid Build Coastguard Worker  '{ ABC=def; def=ghi; echo ${!ABC@ }; } 2>&1 | grep -o bad' 'bad\n' '' ''
537*cf5a6c84SAndroid Build Coastguard Worker# Bash added an error for this between 4.4 and 5.x.
538*cf5a6c84SAndroid Build Coastguard Worker#testing '${!x@ } no match no err' 'echo ${!ABC@ }def' 'def\n' '' ''
539*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing '${!x@ } no match no err2' 'ABC=def; echo ${!ABC@ }ghi' 'ghi\n' '' ''
540*cf5a6c84SAndroid Build Coastguard Workertoyonly testing '${#x::}' 'ABC=abcdefghijklmno; echo ${#ABC:1:2}' '5\n' '' ''
541*cf5a6c84SAndroid Build Coastguard Worker# TODO: ${!abc@x} does _not_ error? And ${PWD@q}
542*cf5a6c84SAndroid Build Coastguard Workertesting '$""' 'ABC=def; echo $"$ABC"' 'def\n' '' ''
543*cf5a6c84SAndroid Build Coastguard Workertesting '"$""" does not nest' 'echo "$"abc""' '$abc\n' '' ''
544*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing '${\}}' 'ABC=ab}cd; echo ${ABC/\}/x}' 'abxcd\n' '' ''
545*cf5a6c84SAndroid Build Coastguard Workertesting 'bad ${^}' '{ echo ${^};} 2>&1 | grep -o bad' 'bad\n' '' ''
546*cf5a6c84SAndroid Build Coastguard Workershxpect '${:} empty len is err' I$'ABC=def; echo ${ABC:}\n' RE'ABC' X
547*cf5a6c84SAndroid Build Coastguard Workertesting '${::} both empty=0' 'ABC=def; echo ${ABC::}' '\n' '' ''
548*cf5a6c84SAndroid Build Coastguard Workertesting '${::} first empty' 'ABC=def; echo ${ABC: : 2 }' 'de\n' '' ''
549*cf5a6c84SAndroid Build Coastguard Workertesting '${::} second empty' 'ABC=def; echo ${ABC: 2 : }' '\n' '' ''
550*cf5a6c84SAndroid Build Coastguard Workertesting '${:}' 'ABC=def; echo ${ABC:1}' 'ef\n' '' ''
551*cf5a6c84SAndroid Build Coastguard Workertesting '${a: }' 'ABC=def; echo ${ABC: 1}' 'ef\n' '' ''
552*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing '${a :}' 'ABC=def; { echo ${ABC :1};} 2>&1 | grep -o bad' 'bad\n' '' ''
553*cf5a6c84SAndroid Build Coastguard Workertesting '${::}' 'ABC=defghi; echo ${ABC:1:2}' 'ef\n' '' ''
554*cf5a6c84SAndroid Build Coastguard Workertesting '${: : }' 'ABC=defghi; echo ${ABC: 1 : 2 }' 'ef\n' '' ''
555*cf5a6c84SAndroid Build Coastguard Workertesting '${::} indirect' \
556*cf5a6c84SAndroid Build Coastguard Worker  'ABC=defghi:1:2; ( echo ${!ABC};) 2>input; [ -s input ] && echo yes' \
557*cf5a6c84SAndroid Build Coastguard Worker  'yes\n' '' ''
558*cf5a6c84SAndroid Build Coastguard Workertesting '${::-}' 'ABC=defghi; echo ${ABC:1:-2}' 'efg\n' '' ''
559*cf5a6c84SAndroid Build Coastguard Workertesting '${:-:-}' 'ABC=defghi; echo ${ABC:-3:2}' 'defghi\n' '' ''
560*cf5a6c84SAndroid Build Coastguard Workertesting '${:-:-}2' 'echo ${ABC:-3:2}' '3:2\n' '' ''
561*cf5a6c84SAndroid Build Coastguard Workertesting '${: -:}' 'ABC=defghi; echo ${ABC: -3:2}' 'gh\n' '' ''
562*cf5a6c84SAndroid Build Coastguard Workertesting '${@%}' 'chicken() { for i in "${@%abc}"; do echo "=$i="; done;}; chicken 1abc 2abc 3abc' '=1=\n=2=\n=3=\n' '' ''
563*cf5a6c84SAndroid Build Coastguard Workertesting '${*%}' 'chicken() { for i in "${*%abc}"; do echo "=$i="; done;}; chicken 1abc 2abc 3abc' '=1 2 3=\n' '' ''
564*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing '${@@Q}' 'xx() { echo "${@@Q}"; }; xx one two three' \
565*cf5a6c84SAndroid Build Coastguard Worker  "'one' 'two' 'three'\n" '' ''
566*cf5a6c84SAndroid Build Coastguard Worker
567*cf5a6c84SAndroid Build Coastguard Workershxpect '${/newline/}' I$'x=$\'\na\';echo ${x/\n' E'> ' I$'/b}\n' O$'ba\n' E'> '
568*cf5a6c84SAndroid Build Coastguard Worker
569*cf5a6c84SAndroid Build Coastguard Workershxpect 'line continuation' I$'echo "hello" \\\n' E'> ' I$'> blah\n' E"$P" \
570*cf5a6c84SAndroid Build Coastguard Worker  I$'wc blah\n' O$'1 1 6 blah\n'
571*cf5a6c84SAndroid Build Coastguard Workershxpect 'line continuation2' I$'echo ABC\\\n' E'> ' I$'DEF\n' O$'ABCDEF\n'
572*cf5a6c84SAndroid Build Coastguard Workertesting "line continuation3" $'ec\\\nho hello' 'hello\n' '' ''
573*cf5a6c84SAndroid Build Coastguard Workertesting "line continuation4" $'if true | \\\n(true);then echo true;fi' 'true\n' '' ''
574*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing "line continuation5" $'XYZ=xyz; echo "abc$\\\nXYZ"' 'abcxyz\n' '' ''
575*cf5a6c84SAndroid Build Coastguard Worker
576*cf5a6c84SAndroid Build Coastguard Worker# Race condition (in bash, but not in toysh) can say 43.
577*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing 'SECONDS' 'readonly SECONDS=41; sleep 1; echo $SECONDS' '42\n' '' ''
578*cf5a6c84SAndroid Build Coastguard Worker# testing 'SECONDS2' 'readonly SECONDS; SECONDS=0; echo $SECONDS' '' '' '' #bash!
579*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing 'SECONDS2' 'SECONDS=123+456; echo $SECONDS' '0\n' '' '' #bash!!
580*cf5a6c84SAndroid Build Coastguard Workertesting '$LINENO 2' $'echo $LINENO\necho $LINENO' '1\n2\n' '' ''
581*cf5a6c84SAndroid Build Coastguard Workertesting '$EUID' 'echo $EUID' "$(id -u)\n" '' ''
582*cf5a6c84SAndroid Build Coastguard Workertesting '$UID' 'echo $UID' "$(id -ur)\n" '' ''
583*cf5a6c84SAndroid Build Coastguard Worker
584*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing 'readonly leading assignment' \
585*cf5a6c84SAndroid Build Coastguard Worker  '{ readonly abc=123;abc=def echo hello; echo $?;} 2>output; grep -o readonly output' \
586*cf5a6c84SAndroid Build Coastguard Worker  'hello\n0\nreadonly\n' '' ''
587*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing 'readonly leading assignment2' \
588*cf5a6c84SAndroid Build Coastguard Worker  'readonly boink=123; export boink; { boink=234 env | grep ^boink=;} 2>/dev/null; echo $?' 'boink=123\n0\n' '' ''
589*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing 'readonly for' \
590*cf5a6c84SAndroid Build Coastguard Worker  'readonly i; for i in one two three; do echo $i; done 2>/dev/null; echo $?' \
591*cf5a6c84SAndroid Build Coastguard Worker  '1\n' '' ''
592*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing 'readonly {}<' \
593*cf5a6c84SAndroid Build Coastguard Worker  'readonly i; echo hello 2>/dev/null {i}</dev/null; echo $?' '1\n' '' ''
594*cf5a6c84SAndroid Build Coastguard Workertesting '$_ 1' 'echo walrus; echo $_' 'walrus\nwalrus\n' '' ''
595*cf5a6c84SAndroid Build Coastguard Workertesting '$_ 2' 'unset _; echo $_' '_\n' '' ''
596*cf5a6c84SAndroid Build Coastguard Worker
597*cf5a6c84SAndroid Build Coastguard Worker# wildcards
598*cf5a6c84SAndroid Build Coastguard Worker
599*cf5a6c84SAndroid Build Coastguard Workertouch walrus wallpapers
600*cf5a6c84SAndroid Build Coastguard Workertesting 'IFS wildcards' \
601*cf5a6c84SAndroid Build Coastguard Worker  'IFS=xy; ABC=abcywal*sxdef; echo $ABC | tr " " "\n" | sort' \
602*cf5a6c84SAndroid Build Coastguard Worker  'abc\ndef\nwallpapers\nwalrus\n' '' ''
603*cf5a6c84SAndroid Build Coastguard Workerrm -f walrus wallpapers
604*cf5a6c84SAndroid Build Coastguard Worker
605*cf5a6c84SAndroid Build Coastguard Worker# Force parsing granularity via interactive shxpect because bash parses all
606*cf5a6c84SAndroid Build Coastguard Worker# of sh -c "str" in one go, meaning the "shopt -s extglob" won't take effect
607*cf5a6c84SAndroid Build Coastguard Worker$BROKEN shxpect 'IFS +(extglob)' I$'shopt -s extglob\n' E"$P" \
608*cf5a6c84SAndroid Build Coastguard Worker  I$'IFS=x; ABC=cxd; for i in +($ABC); do echo =$i=; done\n' \
609*cf5a6c84SAndroid Build Coastguard Worker  O$'=+(c=\n' O$'=d)=\n'
610*cf5a6c84SAndroid Build Coastguard Worker
611*cf5a6c84SAndroid Build Coastguard Workertouch abc\)d
612*cf5a6c84SAndroid Build Coastguard Worker$BROKEN shxpect 'IFS +(extglob) 2' I$'shopt -s extglob\n' E"$P" \
613*cf5a6c84SAndroid Build Coastguard Worker  I$'ABC="c?d"; for i in ab+($ABC); do echo =$i=; done\n' \
614*cf5a6c84SAndroid Build Coastguard Worker  O$'=abc)d=\n'
615*cf5a6c84SAndroid Build Coastguard Workerrm abc\)d
616*cf5a6c84SAndroid Build Coastguard Worker
617*cf5a6c84SAndroid Build Coastguard Worker$BROKEN shxpect '[+(]) overlap priority' I$'shopt -s extglob\n' E"$P" \
618*cf5a6c84SAndroid Build Coastguard Worker  I$'touch "AB[DEF]"; echo AB[+(DEF]) AB[+(DEF)? AB+([DEF)]\n' \
619*cf5a6c84SAndroid Build Coastguard Worker  O$'AB[+(DEF]) AB[DEF] AB+([DEF)]\n' \
620*cf5a6c84SAndroid Build Coastguard Worker  I$'X="("; Y=")"; echo AB[+${X}DEF${Y}?\n' O$'AB[DEF]\n'
621*cf5a6c84SAndroid Build Coastguard Worker
622*cf5a6c84SAndroid Build Coastguard Worker# TODO: syntax error takes out ': ${a?b}; echo $?' (I.E. never runs echo)
623*cf5a6c84SAndroid Build Coastguard Workershxpect '${a?b} sets err, stops cmdline eval' \
624*cf5a6c84SAndroid Build Coastguard Worker  I$': ${a?b} ${c:=d}\n' E E"$P" I$'echo $?$c\n' O$'1\n'
625*cf5a6c84SAndroid Build Coastguard Worker
626*cf5a6c84SAndroid Build Coastguard Worker$BROKEN shxpect 'trace redirect' I$'set -x; echo one\n' E$'+ echo one\n'"$P" O$'one\n' \
627*cf5a6c84SAndroid Build Coastguard Worker  I$'echo two 2>/dev/null\n' O$'two\n' E$'+ echo two\n'"$P" \
628*cf5a6c84SAndroid Build Coastguard Worker  I$'{ echo three; } 2>/dev/null\n' O$'three\n' E"$P"
629*cf5a6c84SAndroid Build Coastguard Workershxpect 'set -u' I$'set -u; echo $walrus\n' REwalrus X
630*cf5a6c84SAndroid Build Coastguard Worker
631*cf5a6c84SAndroid Build Coastguard Workertesting 'source file' 'source input' 'hello\n' 'echo hello \\\n' ''
632*cf5a6c84SAndroid Build Coastguard Workertesting '. file' '. input' 'hello\n' 'echo hello \\\n' ''
633*cf5a6c84SAndroid Build Coastguard Workertesting 'source no newline' 'source input' 'hello \\\n' 'echo hello \\' ''
634*cf5a6c84SAndroid Build Coastguard Workertesting 'source continues' 'echo hello; source <(echo false); echo $?' \
635*cf5a6c84SAndroid Build Coastguard Worker  'hello\n1\n' '' ''
636*cf5a6c84SAndroid Build Coastguard Workertesting 'source returns' 'source <(echo return 37); echo $?' '37\n' '' ''
637*cf5a6c84SAndroid Build Coastguard Workertesting 'source is live' \
638*cf5a6c84SAndroid Build Coastguard Worker  'for i in one two three; do echo "echo $i" > input; source input; done' \
639*cf5a6c84SAndroid Build Coastguard Worker  'one\ntwo\nthree\n' 'x' ''
640*cf5a6c84SAndroid Build Coastguard Workertesting 'source is live in functions' \
641*cf5a6c84SAndroid Build Coastguard Worker  'func() { source input; }; for i in one two three; do echo echo $i > input; func; done' \
642*cf5a6c84SAndroid Build Coastguard Worker  'one\ntwo\nthree\n' 'x' ''
643*cf5a6c84SAndroid Build Coastguard Workertesting 'subshell inheritance' \
644*cf5a6c84SAndroid Build Coastguard Worker  'func() { source input; cat <(echo $xx; xx=456; echo $xx); echo $xx;}; echo local xx=123 > input; func; echo $xx' \
645*cf5a6c84SAndroid Build Coastguard Worker  '123\n456\n123\n\n' 'x' ''
646*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing 'semicolon vs newline' \
647*cf5a6c84SAndroid Build Coastguard Worker  'source input 2>/dev/null || echo yes' 'one\nyes\n' \
648*cf5a6c84SAndroid Build Coastguard Worker  'echo one\necho two; echo |' ''
649*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing 'syntax err pops to source but encapsulating function continues' \
650*cf5a6c84SAndroid Build Coastguard Worker  'func() { echo one; source <(echo -e "echo hello\necho |") 2>/dev/null; echo three;}; func; echo four' \
651*cf5a6c84SAndroid Build Coastguard Worker  'one\nhello\nthree\nfour\n' '' ''
652*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing '"exit shell" means exit eval but encapsulating function continues' \
653*cf5a6c84SAndroid Build Coastguard Worker  'func() { eval "echo one; echo \${?potato}; echo and" 2>/dev/null; echo plus;}; func; echo then' \
654*cf5a6c84SAndroid Build Coastguard Worker  'one\nplus\nthen\n' '' ''
655*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing 'return needs function or source' \
656*cf5a6c84SAndroid Build Coastguard Worker  'cat <(return 0 2>/dev/null; echo $?); echo after' '2\nafter\n' '' ''
657*cf5a6c84SAndroid Build Coastguard Workertesting 'return nests' 'y(){ x; return $((3+$?));};x(){ return 5; };y;echo $?' \
658*cf5a6c84SAndroid Build Coastguard Worker  '8\n' '' ''
659*cf5a6c84SAndroid Build Coastguard Worker
660*cf5a6c84SAndroid Build Coastguard Workershxpect "functions need block" I$'x() echo;\n' RE'[Ss]yntax [Ee]rror' X2
661*cf5a6c84SAndroid Build Coastguard Workertesting 'functions() {} in same PID' \
662*cf5a6c84SAndroid Build Coastguard Worker  '{ echo $BASHPID; chicken() { echo $BASHPID;}; chicken;} | sort -u | wc -l' '1\n' '' ''
663*cf5a6c84SAndroid Build Coastguard Workertesting 'functions() () different PID' \
664*cf5a6c84SAndroid Build Coastguard Worker  '{ echo $BASHPID; chicken() ( echo $BASHPID;); chicken;} | sort -u | wc -l' '2\n' '' ''
665*cf5a6c84SAndroid Build Coastguard Workertesting 'function() just wants any block span' \
666*cf5a6c84SAndroid Build Coastguard Worker  'func() if true; then echo hello; fi; echo one; func; echo two' \
667*cf5a6c84SAndroid Build Coastguard Worker  'one\nhello\ntwo\n' '' ''
668*cf5a6c84SAndroid Build Coastguard Workertesting 'function alternate syntax' \
669*cf5a6c84SAndroid Build Coastguard Worker  'function func if true; then echo hello; fi; echo one; func; echo two' \
670*cf5a6c84SAndroid Build Coastguard Worker  'one\nhello\ntwo\n' '' ''
671*cf5a6c84SAndroid Build Coastguard Workertesting 'function syntax 3' \
672*cf5a6c84SAndroid Build Coastguard Worker  'function func ( ) if true; then echo hello; fi; echo one; func; echo two' \
673*cf5a6c84SAndroid Build Coastguard Worker  'one\nhello\ntwo\n' '' ''
674*cf5a6c84SAndroid Build Coastguard Workertesting 'function nested parentheses' \
675*cf5a6c84SAndroid Build Coastguard Worker  '( potato() { echo aaa; }; potato )' 'aaa\n' '' ''
676*cf5a6c84SAndroid Build Coastguard Workershxpect 'local creates a whiteout' \
677*cf5a6c84SAndroid Build Coastguard Worker  I$'func() { local potato; echo ${potato?bang}; }; potato=123; func\n' \
678*cf5a6c84SAndroid Build Coastguard Worker  E E"$P" I$'echo $?\n' O$'1\n'
679*cf5a6c84SAndroid Build Coastguard Workertesting 'local replaces/preserves magic type' \
680*cf5a6c84SAndroid Build Coastguard Worker  'x() { local RANDOM=potato; echo $RANDOM;};x;echo -e "$RANDOM\n$RANDOM"|wc -l'\
681*cf5a6c84SAndroid Build Coastguard Worker  'potato\n2\n' '' ''
682*cf5a6c84SAndroid Build Coastguard Worker
683*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing '$$ is parent shell' \
684*cf5a6c84SAndroid Build Coastguard Worker  '{ echo $$; (echo $$) } | sort -u | wc -l' "1\n" "" ""
685*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing '$PPID is parent shell' \
686*cf5a6c84SAndroid Build Coastguard Worker  '{ echo $PPID; (echo $PPID) } | sort -u | wc -l' "1\n" "" ""
687*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing '$BASHPID is current PID' \
688*cf5a6c84SAndroid Build Coastguard Worker  '{ echo $BASHPID; (echo $BASHPID) } | sort -u | wc -l' "2\n" "" ""
689*cf5a6c84SAndroid Build Coastguard Worker
690*cf5a6c84SAndroid Build Coastguard Workertesting 'unexport supports +=' 'export -n ABC+=DEF; declare -p ABC' \
691*cf5a6c84SAndroid Build Coastguard Worker  'declare -- ABC="DEF"\n' '' ''
692*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing 'unexport existing +=' \
693*cf5a6c84SAndroid Build Coastguard Worker  'export ABC=XYZ; export -n ABC+=DEF; declare -p ABC' \
694*cf5a6c84SAndroid Build Coastguard Worker  'declare -- ABC="XYZDEF"\n' '' ''
695*cf5a6c84SAndroid Build Coastguard Worker
696*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing '$!' '{ echo $BASHPID & echo $!; echo ${!};} | sort -u | wc -l' '1\n' \
697*cf5a6c84SAndroid Build Coastguard Worker  '' ''
698*cf5a6c84SAndroid Build Coastguard Worker
699*cf5a6c84SAndroid Build Coastguard Workershxpect 'blank line preserves $?' \
700*cf5a6c84SAndroid Build Coastguard Worker  I$'false\n' E"$P" I$'\n' E"$P" I$'echo $?\n' O$'1\n'
701*cf5a6c84SAndroid Build Coastguard Workertesting 'NOP line clears $?' 'false;$NOTHING;echo $?' '0\n' '' ''
702*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing 'run "$@"' 'false;"$@";echo $?' '0\n' '' ''
703*cf5a6c84SAndroid Build Coastguard Worker
704*cf5a6c84SAndroid Build Coastguard Worker# "Word splitting... not performed on the words between the [[ and ]]"
705*cf5a6c84SAndroid Build Coastguard Workertesting '[[split1]]' 'A="1 -lt 2"; [[ $A ]] && echo yes' 'yes\n' '' ''
706*cf5a6c84SAndroid Build Coastguard Workertesting '[[split2]]' 'A="2 -lt 1"; [[ $A ]] && echo yes' 'yes\n' '' ''
707*cf5a6c84SAndroid Build Coastguard Workertesting '[[split3]]' \
708*cf5a6c84SAndroid Build Coastguard Worker  'A="2 -lt 1"; [[ -e $A ]] && echo one; touch "$A" && [[ -e $A ]] && echo two'\
709*cf5a6c84SAndroid Build Coastguard Worker  'two\n' '' ''
710*cf5a6c84SAndroid Build Coastguard Workerrm -f '2 -lt 1'
711*cf5a6c84SAndroid Build Coastguard Workertesting '[[split4]]' \
712*cf5a6c84SAndroid Build Coastguard Worker  '[[ $(cat) == "a b" ]] <<< "a b" > potato && rm potato && echo ok' \
713*cf5a6c84SAndroid Build Coastguard Worker  'ok\n' '' ''
714*cf5a6c84SAndroid Build Coastguard Worker$BROKEN testing '[[split5]]' \
715*cf5a6c84SAndroid Build Coastguard Worker  '[[ $(cat) == "a b" ]] < <(echo a b) > potato && rm potato && echo ok' \
716*cf5a6c84SAndroid Build Coastguard Worker  'ok\n' '' ''
717*cf5a6c84SAndroid Build Coastguard Worker# And token parsing leaking through: 1>2 is an error, 1 >2 is not
718*cf5a6c84SAndroid Build Coastguard Workertesting '[[1>2]] is not a redirect' '[[ 1 >2 ]] || [ -e 2 ] || echo yup' \
719*cf5a6c84SAndroid Build Coastguard Worker  'yup\n' '' ''
720*cf5a6c84SAndroid Build Coastguard Workertesting "[[1 >0]] doesn't need that second space" \
721*cf5a6c84SAndroid Build Coastguard Worker  '[[ 1 >0 ]] && { [ -e 2 ] || echo yup; }' 'yup\n' '' ''
722*cf5a6c84SAndroid Build Coastguard Workertesting '[[1<2]] is alphabetical, not numeric' '[[ 123 < 19 ]] && echo yes' \
723*cf5a6c84SAndroid Build Coastguard Worker  'yes\n' '' ''
724*cf5a6c84SAndroid Build Coastguard Workertesting '[[~]]' '[[ ~ == $HOME ]] && echo yes' 'yes\n' '' ''
725*cf5a6c84SAndroid Build Coastguard Worker
726*cf5a6c84SAndroid Build Coastguard Worker# The trailing space is because the \n gets stripped off otherwise
727*cf5a6c84SAndroid Build Coastguard Workertesting 'quoting contexts nest' \
728*cf5a6c84SAndroid Build Coastguard Worker  $'echo -n "$(echo "hello $(eval $\'echo -\\\\\\ne \\\'world\\n \\\'\')")"' \
729*cf5a6c84SAndroid Build Coastguard Worker  'hello world\n ' '' ''
730*cf5a6c84SAndroid Build Coastguard Workertesting "\$'' suppresses variable expansion" \
731*cf5a6c84SAndroid Build Coastguard Worker  $'echo $\'$(abc\'' '$(abc\n' '' ''
732*cf5a6c84SAndroid Build Coastguard Worker
733*cf5a6c84SAndroid Build Coastguard Workertesting 'if; is a syntax error but if $EMPTY; is not' \
734*cf5a6c84SAndroid Build Coastguard Worker  'if $NONE; then echo hello; fi' 'hello\n' '' ''
735*cf5a6c84SAndroid Build Coastguard Worker
736*cf5a6c84SAndroid Build Coastguard Worker# TODO finish variable list from shell init
737*cf5a6c84SAndroid Build Coastguard Worker
738*cf5a6c84SAndroid Build Coastguard Worker# $# $? $- $! $0  # $$
739*cf5a6c84SAndroid Build Coastguard Worker# always exported: PWD SHLVL _
740*cf5a6c84SAndroid Build Coastguard Worker#  ./bash -c 'echo $_' prints $BASH, but PATH search shows path? Hmmm...
741*cf5a6c84SAndroid Build Coastguard Worker# ro: UID PPID EUID $
742*cf5a6c84SAndroid Build Coastguard Worker# IFS LINENO
743*cf5a6c84SAndroid Build Coastguard Worker# PATH HOME SHELL USER LOGNAME SHLVL HOSTNAME HOSTTYPE MACHTYPE OSTYPE OLDPWD
744*cf5a6c84SAndroid Build Coastguard Worker# PS0 PS1='$ ' PS2='> ' PS3 PS4 BASH BASH_VERSION
745*cf5a6c84SAndroid Build Coastguard Worker# ENV - if [ -n "$ENV" ]; then . "$ENV"; fi # BASH_ENV - synonym for ENV
746*cf5a6c84SAndroid Build Coastguard Worker# FUNCNEST - maximum function nesting level (abort when above)
747*cf5a6c84SAndroid Build Coastguard Worker# REPLY - set by input with no args
748*cf5a6c84SAndroid Build Coastguard Worker# OPTARG OPTIND - set by getopts builtin
749*cf5a6c84SAndroid Build Coastguard Worker# OPTERR
750*cf5a6c84SAndroid Build Coastguard Worker
751*cf5a6c84SAndroid Build Coastguard Worker# maybe not: EXECIGNORE, FIGNORE, GLOBIGNORE
752*cf5a6c84SAndroid Build Coastguard Worker
753*cf5a6c84SAndroid Build Coastguard Worker#BASH_SUBSHELL - SHLVL synonym
754*cf5a6c84SAndroid Build Coastguard Worker#BASH_EXECUTION_STRING - -c argument
755*cf5a6c84SAndroid Build Coastguard Worker#
756*cf5a6c84SAndroid Build Coastguard Worker#automatically set:
757*cf5a6c84SAndroid Build Coastguard Worker#OPTARG - set by getopts builtin
758*cf5a6c84SAndroid Build Coastguard Worker#OPTIND - set by getopts builtin
759*cf5a6c84SAndroid Build Coastguard Worker#
760*cf5a6c84SAndroid Build Coastguard Worker#PROMPT_COMMAND PROMPT_DIRTRIM PS0 PS1 PS2 PS3 PS4
761*cf5a6c84SAndroid Build Coastguard Worker#
762*cf5a6c84SAndroid Build Coastguard Worker#unsettable (assignments ignored before then)
763*cf5a6c84SAndroid Build Coastguard Worker#LINENO SECONDS RANDOM
764*cf5a6c84SAndroid Build Coastguard Worker#GROUPS - id -g
765*cf5a6c84SAndroid Build Coastguard Worker#HISTCMD - history number
766*cf5a6c84SAndroid Build Coastguard Worker#
767*cf5a6c84SAndroid Build Coastguard Worker#TMOUT - used by read
768*cf5a6c84SAndroid Build Coastguard Worker
769*cf5a6c84SAndroid Build Coastguard Worker# does not match: ./sh -c 'echo {a..Z}' becomes a ` _ ^ ] \ [ Z
770*cf5a6c84SAndroid Build Coastguard Worker
771*cf5a6c84SAndroid Build Coastguard Worker# commit ec6639407b9e
772*cf5a6c84SAndroid Build Coastguard Worker#-  IS_TOYBOX_RE='(toybox|This is not GNU).*'
773*cf5a6c84SAndroid Build Coastguard Worker#-  [[ "$IS_TOYBOX" =~ $IS_TOYBOX_RE ]] || SKIPNEXT=1
774*cf5a6c84SAndroid Build Coastguard Worker#+  case "$IS_TOYBOX" in
775*cf5a6c84SAndroid Build Coastguard Worker#+    toybox*) ;;
776*cf5a6c84SAndroid Build Coastguard Worker#+    This\ is\ not\ GNU*) ;;
777*cf5a6c84SAndroid Build Coastguard Worker#+    *) SKIPNEXT=1 ;;
778*cf5a6c84SAndroid Build Coastguard Worker#+  esac
779*cf5a6c84SAndroid Build Coastguard Worker
780*cf5a6c84SAndroid Build Coastguard Worker# TODO: categorize tests
781*cf5a6c84SAndroid Build Coastguard Worker
782*cf5a6c84SAndroid Build Coastguard Worker# TODO https://mywiki.wooledge.org/BashFAQ
783*cf5a6c84SAndroid Build Coastguard Worker#   http://tiswww.case.edu/php/chet/bash/FAQ
784*cf5a6c84SAndroid Build Coastguard Worker#   https://mywiki.wooledge.org/BashPitfalls#set_-euo_pipefail
785*cf5a6c84SAndroid Build Coastguard Worker
786*cf5a6c84SAndroid Build Coastguard Worker#        // ${#} ${#x} ${#@} ${#x[@]} ${#!} ${!#}
787*cf5a6c84SAndroid Build Coastguard Worker#        // ${!} ${!@} ${!@Q} ${!x} ${!x@} ${!x@Q} ${!x#} ${!x[} ${!x[*]}
788*cf5a6c84SAndroid Build Coastguard Worker
789*cf5a6c84SAndroid Build Coastguard Worker# Looked like a prefix but wasn't: three chars (@ # -) are both paremeter name
790*cf5a6c84SAndroid Build Coastguard Worker# and slice operator. When immediately followed by } it's parameter, otherwise
791*cf5a6c84SAndroid Build Coastguard Worker# we did NOT have a prefix and it's an operator.
792*cf5a6c84SAndroid Build Coastguard Worker#
793*cf5a6c84SAndroid Build Coastguard Worker# ${#-} ${#-abc}
794*cf5a6c84SAndroid Build Coastguard Worker# ${##} ${##0}
795*cf5a6c84SAndroid Build Coastguard Worker# ${#@} ${#@Q}
796*cf5a6c84SAndroid Build Coastguard Worker#
797*cf5a6c84SAndroid Build Coastguard Worker# backslash not discarded: echo "abc\"def"
798*cf5a6c84SAndroid Build Coastguard Worker
799*cf5a6c84SAndroid Build Coastguard Worker# ${x:-y} use default
800*cf5a6c84SAndroid Build Coastguard Worker# ${x:=y} assign default (error if positional)
801*cf5a6c84SAndroid Build Coastguard Worker# ${x:?y} err if null
802*cf5a6c84SAndroid Build Coastguard Worker# ${x:+y} alt value
803*cf5a6c84SAndroid Build Coastguard Worker# ${x:off} ${x:off:len} off<0 from end (must ": -"), len<0 also from end must
804*cf5a6c84SAndroid Build Coastguard Worker#   0-based indexing
805*cf5a6c84SAndroid Build Coastguard Worker# ${@:off:len} positional parameters, off -1 = len, -len is error
806*cf5a6c84SAndroid Build Coastguard Worker#   1-based indexing
807*cf5a6c84SAndroid Build Coastguard Worker
808*cf5a6c84SAndroid Build Coastguard Worker# [] wins over +()
809*cf5a6c84SAndroid Build Coastguard Worker# touch 'AB[DEF]'; echo AB[+(DEF]) AB[+(DEF)?
810*cf5a6c84SAndroid Build Coastguard Worker# AB[+(DEF]) AB[DEF]
811*cf5a6c84SAndroid Build Coastguard Worker
812*cf5a6c84SAndroid Build Coastguard Worker# Testing shell corner cases _within_ a shell script is kind of hard.
813