1 #!/usr/bin/env bash
2
3 #### case
4 foo=a; case $foo in [0-9]) echo number;; [a-z]) echo letter;; esac
5 ## stdout: letter
6
7 #### case in subshell
8 # Hm this subhell has to know about the closing ) and stuff like that.
9 # case_clause is a compound_command, which is a command. And a subshell
10 # takes a compound_list, which is a list of terms, which has and_ors in them
11 # ... which eventually boils down to a command.
12 echo $(foo=a; case $foo in [0-9]) echo number;; [a-z]) echo letter;; esac)
13 ## stdout: letter
14
15 #### Command sub word part
16 # "The token shall not be delimited by the end of the substitution."
17 foo=FOO; echo $(echo $foo)bar$(echo $foo)
18 ## stdout: FOObarFOO
19
20 #### Backtick
21 foo=FOO; echo `echo $foo`bar`echo $foo`
22 ## stdout: FOObarFOO
23
24 #### Backtick 2
25 echo `echo -n l; echo -n s`
26 ## stdout: ls
27
28 #### Nested backticks
29 # Inner `` are escaped! Not sure how to do triple.. Seems like an unlikely
30 # use case. Not sure if I even want to support this!
31 echo X > $TMP/000000-first
32 echo `\`echo -n l; echo -n s\` $TMP | grep 000000-first`
33 ## stdout: 000000-first
34
35 #### Making command out of command sub should work
36 # Works in bash and dash!
37 $(echo ec)$(echo ho) split builtin
38 ## stdout: split builtin
39
40 #### Making keyword out of command sub should NOT work
41 # This doesn't work in bash or dash! Hm builtins are different than keywords /
42 # reserved words I guess.
43 # dash fails, but gives code 0
44 $(echo f)$(echo or) i in a b c; do echo $i; done
45 echo status=$?
46 ## stdout-json: ""
47 ## status: 2
48 ## BUG dash stdout-json: "\nstatus=0\n"
49 ## BUG dash status: 0
50 ## OK mksh status: 1
51
52 #### Command sub with here doc
53 echo $(<<EOF tac
54 one
55 two
56 EOF
57 )
58 ## stdout: two one
59
60 #### Here doc with pipeline
61 <<EOF tac | tr '\n' 'X'
62 one
63 two
64 EOF
65 ## stdout-json: "twoXoneX"
66
67 #### Command Sub word split
68 argv.py $(echo 'hi there') "$(echo 'hi there')"
69 ## stdout: ['hi', 'there', 'hi there']
70
71 #### Command Sub trailing newline removed
72 s=$(python -c 'print "ab\ncd\n"')
73 argv.py "$s"
74 ## stdout: ['ab\ncd']
75
76 #### Command Sub trailing whitespace not removed
77 s=$(python -c 'print "ab\ncd\n "')
78 argv.py "$s"
79 ## stdout: ['ab\ncd\n ']
80
81 #### Command Sub and exit code
82 # A command resets the exit code, but an assignment doesn't.
83 echo $(echo x; exit 33)
84 echo $?
85 x=$(echo x; exit 33)
86 echo $?
87 ## STDOUT:
88 x
89 0
90 33
91 ## END
92
93 #### Command Sub in local sets exit code
94 # A command resets the exit code, but an assignment doesn't.
95 f() {
96 echo $(echo x; exit 33)
97 echo $?
98 local x=$(echo x; exit 33)
99 echo $?
100 }
101 f
102 ## STDOUT:
103 x
104 0
105 0
106 ## END
107
108 #### Double Quotes in Command Sub in Double Quotes
109 # virtualenv's bin/activate uses this.
110 # This is weird! Double quotes within `` is different than double quotes
111 # within $()! All shells agree.
112 # I think this is related to the nested backticks case!
113 echo "x $(echo hi)"
114 echo "x $(echo "hi")"
115 echo "x $(echo \"hi\")"
116 echo "x `echo hi`"
117 echo "x `echo "hi"`"
118 echo "x `echo \"hi\"`"
119 ## STDOUT:
120 x hi
121 x hi
122 x "hi"
123 x hi
124 x hi
125 x hi
126 ## END
127
128 #### Escaped quote in [[ ]]
129 file=$TMP/command-sub-dbracket
130 #rm -f $file
131 echo "123 `[[ $(echo \\" > $file) ]]` 456";
132 cat $file
133 ## STDOUT:
134 123 456
135 "
136 ## END
137
138 #### Quoting $ within ``
139 echo 1 `echo $`
140 echo 2 `echo \$`
141 echo 3 `echo \\$`
142 echo 4 `echo \\\$`
143 echo 5 `echo \\\\$`
144 ## STDOUT:
145 1 $
146 2 $
147 3 $
148 4 $
149 5 \$
150 ## END
151
152 #### Quoting $ within `` within double quotes
153 echo "1 `echo $`"
154 echo "2 `echo \$`"
155 echo "3 `echo \\$`"
156 echo "4 `echo \\\$`"
157 echo "5 `echo \\\\$`"
158 ## STDOUT:
159 1 $
160 2 $
161 3 $
162 4 $
163 5 \$
164 ## END
165
166 #### Quoting \ within ``
167 # You need FOUR backslashes to make a literal \.
168 echo [1 `echo \ `]
169 echo [2 `echo \\ `]
170 echo [3 `echo \\\\ `]
171 ## STDOUT:
172 [1 ]
173 [2 ]
174 [3 \]
175 ## END
176
177 #### Quoting \ within `` within double quotes
178 echo "[1 `echo \ `]"
179 echo "[2 `echo \\ `]"
180 echo "[3 `echo \\\\ `]"
181 ## STDOUT:
182 [1 ]
183 [2 ]
184 [3 \]
185 ## END
186
187 #### Quoting ( within ``
188 echo 1 `echo \(`
189 echo 2 `echo \\(`
190 echo 3 `echo \\ \\(`
191 ## STDOUT:
192 1 (
193 2 (
194 3 (
195 ## END
196
197 #### Quoting ( within `` within double quotes
198 echo "1 `echo \(`"
199 echo "2 `echo \\(`"
200 echo "3 `echo \\ \\(`"
201 ## STDOUT:
202 1 (
203 2 (
204 3 (
205 ## END
206
207 #### Quoting non-special characters within ``
208 echo [1 `echo \z]`
209 echo [2 `echo \\z]`
210 echo [3 `echo \\\z]`
211 echo [4 `echo \\\\z]`
212 ## STDOUT:
213 [1 z]
214 [2 z]
215 [3 \z]
216 [4 \z]
217 ## END
218
219 #### Quoting non-special characters within `` within double quotes
220 echo "[1 `echo \z`]"
221 echo "[2 `echo \\z`]"
222 echo "[3 `echo \\\z`]"
223 echo "[4 `echo \\\\z`]"
224 ## STDOUT:
225 [1 z]
226 [2 z]
227 [3 \z]
228 [4 \z]
229 ## END
230
231 #### Quoting double quotes within backticks
232 echo \"foo\" # for comparison
233 echo `echo \"foo\"`
234 echo `echo \\"foo\\"`
235 ## STDOUT:
236 "foo"
237 "foo"
238 "foo"
239 ## END
240
241 # Documented in doc/known-differences.md (and Morbig paper brought up the same
242 # issue)
243 ## OK osh STDOUT:
244 "foo"
245 foo
246 "foo"
247 ## END
248
249 #### More levels of double quotes in backticks
250 # Shells don't agree here, some of them give you form feeds!
251 # There are two levels of processing I don't understand.
252 echo BUG
253 exit
254 echo `echo \\\"foo\\\"`
255 echo `echo \\\\"foo\\\\"`
256 echo `echo \\\\\"foo\\\\\"`
257 ## BUG bash/dash/mksh/osh STDOUT:
258 BUG
259 ## END
260
261 #### Syntax errors with double quotes within backticks
262
263 # bash does print syntax errors but somehow it exits 0
264
265 $SH -c 'echo `echo "`'
266 echo status=$?
267 $SH -c 'echo `echo \\\\"`'
268 echo status=$?
269
270 ## STDOUT:
271 status=2
272 status=2
273 ## END
274 ## OK mksh STDOUT:
275 status=1
276 status=1
277 ## END
278 ## OK bash stdout-json: "\nstatus=0\n\nstatus=0\n"