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 $(echo f)$(echo or) i in a b c; do echo $i; done
42 echo status=$?
43 ## stdout-json: ""
44 ## status: 2
45 ## OK mksh status: 1
46
47 #### Command sub with here doc
48 echo $(<<EOF tac
49 one
50 two
51 EOF
52 )
53 ## stdout: two one
54
55 #### Here doc with pipeline
56 <<EOF tac | tr '\n' 'X'
57 one
58 two
59 EOF
60 ## stdout-json: "twoXoneX"
61
62 #### Command Sub word split
63 argv.py $(echo 'hi there') "$(echo 'hi there')"
64 ## stdout: ['hi', 'there', 'hi there']
65
66 #### Command Sub trailing newline removed
67 s=$(python -c 'print("ab\ncd\n")')
68 argv.py "$s"
69 ## stdout: ['ab\ncd']
70
71 #### Command Sub trailing whitespace not removed
72 s=$(python -c 'print("ab\ncd\n ")')
73 argv.py "$s"
74 ## stdout: ['ab\ncd\n ']
75
76 #### Command Sub and exit code
77 # A command resets the exit code, but an assignment doesn't.
78 echo $(echo x; exit 33)
79 echo $?
80 x=$(echo x; exit 33)
81 echo $?
82 ## STDOUT:
83 x
84 0
85 33
86 ## END
87
88 #### Command Sub in local sets exit code
89 # A command resets the exit code, but an assignment doesn't.
90 f() {
91 echo $(echo x; exit 33)
92 echo $?
93 local x=$(echo x; exit 33)
94 echo $?
95 }
96 f
97 ## STDOUT:
98 x
99 0
100 0
101 ## END
102
103 #### Double Quotes in Command Sub in Double Quotes
104 # virtualenv's bin/activate uses this.
105 # This is weird! Double quotes within `` is different than double quotes
106 # within $()! All shells agree.
107 # I think this is related to the nested backticks case!
108 echo "x $(echo hi)"
109 echo "x $(echo "hi")"
110 echo "x $(echo \"hi\")"
111 echo "x `echo hi`"
112 echo "x `echo "hi"`"
113 echo "x `echo \"hi\"`"
114 ## STDOUT:
115 x hi
116 x hi
117 x "hi"
118 x hi
119 x hi
120 x hi
121 ## END
122
123 #### Escaped quote in [[ ]]
124 file=$TMP/command-sub-dbracket
125 #rm -f $file
126 echo "123 `[[ $(echo \\" > $file) ]]` 456";
127 cat $file
128 ## STDOUT:
129 123 456
130 "
131 ## END
132
133 #### Quoting $ within ``
134 echo 1 `echo $`
135 echo 2 `echo \$`
136 echo 3 `echo \\$`
137 echo 4 `echo \\\$`
138 echo 5 `echo \\\\$`
139 ## STDOUT:
140 1 $
141 2 $
142 3 $
143 4 $
144 5 \$
145 ## END
146
147 #### Quoting $ within `` within double quotes
148 echo "1 `echo $`"
149 echo "2 `echo \$`"
150 echo "3 `echo \\$`"
151 echo "4 `echo \\\$`"
152 echo "5 `echo \\\\$`"
153 ## STDOUT:
154 1 $
155 2 $
156 3 $
157 4 $
158 5 \$
159 ## END
160
161 #### Quoting \ within ``
162 # You need FOUR backslashes to make a literal \.
163 echo [1 `echo \ `]
164 echo [2 `echo \\ `]
165 echo [3 `echo \\\\ `]
166 ## STDOUT:
167 [1 ]
168 [2 ]
169 [3 \]
170 ## END
171
172 #### Quoting \ within `` within double quotes
173 echo "[1 `echo \ `]"
174 echo "[2 `echo \\ `]"
175 echo "[3 `echo \\\\ `]"
176 ## STDOUT:
177 [1 ]
178 [2 ]
179 [3 \]
180 ## END
181
182 #### Quoting ( within ``
183 echo 1 `echo \(`
184 echo 2 `echo \\(`
185 echo 3 `echo \\ \\(`
186 ## STDOUT:
187 1 (
188 2 (
189 3 (
190 ## END
191
192 #### Quoting ( within `` within double quotes
193 echo "1 `echo \(`"
194 echo "2 `echo \\(`"
195 echo "3 `echo \\ \\(`"
196 ## STDOUT:
197 1 (
198 2 (
199 3 (
200 ## END
201
202 #### Quoting non-special characters within ``
203 echo [1 `echo \z]`
204 echo [2 `echo \\z]`
205 echo [3 `echo \\\z]`
206 echo [4 `echo \\\\z]`
207 ## STDOUT:
208 [1 z]
209 [2 z]
210 [3 \z]
211 [4 \z]
212 ## END
213
214 #### Quoting non-special characters within `` within double quotes
215 echo "[1 `echo \z`]"
216 echo "[2 `echo \\z`]"
217 echo "[3 `echo \\\z`]"
218 echo "[4 `echo \\\\z`]"
219 ## STDOUT:
220 [1 z]
221 [2 z]
222 [3 \z]
223 [4 \z]
224 ## END
225
226 #### Quoting double quotes within backticks
227 echo \"foo\" # for comparison
228 echo `echo \"foo\"`
229 echo `echo \\"foo\\"`
230 ## STDOUT:
231 "foo"
232 "foo"
233 "foo"
234 ## END
235
236 # Documented in doc/known-differences.md (and Morbig paper brought up the same
237 # issue)
238 ## OK osh STDOUT:
239 "foo"
240 foo
241 "foo"
242 ## END
243
244 #### More levels of double quotes in backticks
245 # Shells don't agree here, some of them give you form feeds!
246 # There are two levels of processing I don't understand.
247 echo BUG
248 exit
249 echo `echo \\\"foo\\\"`
250 echo `echo \\\\"foo\\\\"`
251 echo `echo \\\\\"foo\\\\\"`
252 ## BUG bash/dash/mksh/osh STDOUT:
253 BUG
254 ## END
255
256 #### Syntax errors with double quotes within backticks
257
258 # bash does print syntax errors but somehow it exits 0
259
260 $SH -c 'echo `echo "`'
261 echo status=$?
262 $SH -c 'echo `echo \\\\"`'
263 echo status=$?
264
265 ## STDOUT:
266 status=2
267 status=2
268 ## END
269 ## OK mksh STDOUT:
270 status=1
271 status=1
272 ## END
273 ## OK bash stdout-json: "\nstatus=0\n\nstatus=0\n"