1 ## oils_failures_allowed: 0
2 ## compare_shells: dash bash mksh zsh
3
4
5 #### Print shell strings with weird chars: set and printf %q and ${x@Q}
6
7 # bash declare -p will print binary data, which makes this invalid UTF-8!
8 foo=$(/bin/echo -e 'a\nb\xffc'\'d)
9
10 # let's test the easier \x01, which doesn't give bash problems
11 foo=$(/bin/echo -e 'a\nb\x01c'\'d)
12
13 # dash:
14 # only supports 'set'; prints it on multiple lines with binary data
15 # switches to "'" for single quotes, not \'
16 # zsh:
17 # print binary data all the time, except for printf %q
18 # does print $'' strings
19 # mksh:
20 # prints binary data for @Q
21 # prints $'' strings
22
23 # All are very inconsistent.
24
25 case $SH in dash|mksh|zsh) return ;; esac
26
27
28 set | grep -A1 foo
29
30 # Will print multi-line and binary data literally!
31 #declare -p foo
32
33 printf 'pf %q\n' "$foo"
34
35 echo '@Q ' ${foo@Q}
36
37 ## STDOUT:
38 foo=$'a\nb\u0001c\'d'
39 pf $'a\nb\u0001c\'d'
40 @Q $'a\nb\u0001c\'d'
41 ## END
42
43 ## OK bash STDOUT:
44 foo=$'a\nb\001c\'d'
45 pf $'a\nb\001c\'d'
46 @Q $'a\nb\001c\'d'
47 ## END
48
49 ## OK dash/mksh/zsh STDOUT:
50 ## END
51
52 #### Print shell strings with normal chars: set and printf %q and ${x@Q}
53
54 # There are variations on whether quotes are printed
55
56 case $SH in dash|zsh) return ;; esac
57
58 foo=spam
59
60 set | grep -A1 foo
61
62 # Will print multi-line and binary data literally!
63 typeset -p foo
64
65 printf 'pf %q\n' "$foo"
66
67 echo '@Q ' ${foo@Q}
68
69 ## STDOUT:
70 foo=spam
71 declare -- foo=spam
72 pf spam
73 @Q spam
74 ## END
75
76
77 ## OK bash STDOUT:
78 foo=spam
79 declare -- foo="spam"
80 pf spam
81 @Q 'spam'
82 ## END
83
84 ## OK mksh STDOUT:
85 foo=spam
86 typeset foo=spam
87 pf spam
88 @Q spam
89 ## END
90
91 ## N-I dash/zsh STDOUT:
92 ## END
93
94
95
96 #### command -v
97 myfunc() { echo x; }
98 command -v echo
99 echo $?
100 command -v myfunc
101 echo $?
102 command -v nonexistent # doesn't print anything
103 echo $?
104 command -v for
105 echo $?
106 ## STDOUT:
107 echo
108 0
109 myfunc
110 0
111 1
112 for
113 0
114 ## OK dash STDOUT:
115 echo
116 0
117 myfunc
118 0
119 127
120 for
121 0
122 ## END
123
124 #### command -v with multiple names
125 # ALL FOUR SHELLS behave differently here!
126 #
127 # bash chooses to swallow the error! We agree with zsh if ANY word lookup
128 # fails, then the whole thing fails.
129
130 myfunc() { echo x; }
131 command -v echo myfunc ZZZ for
132 echo status=$?
133
134 ## STDOUT:
135 echo
136 myfunc
137 for
138 status=1
139 ## BUG bash STDOUT:
140 echo
141 myfunc
142 for
143 status=0
144 ## BUG dash STDOUT:
145 echo
146 status=0
147 ## OK mksh STDOUT:
148 echo
149 myfunc
150 status=1
151 ## END
152
153 #### command -v doesn't find non-executable file
154 # PATH resolution is different
155
156 PATH="_tmp:$PATH"
157 touch _tmp/non-executable _tmp/executable
158 chmod +x _tmp/executable
159
160 command -v _tmp/non-executable
161 echo status=$?
162
163 command -v _tmp/executable
164 echo status=$?
165
166 ## STDOUT:
167 status=1
168 _tmp/executable
169 status=0
170 ## END
171
172 ## BUG dash STDOUT:
173 _tmp/non-executable
174 status=0
175 _tmp/executable
176 status=0
177 ## END
178
179 #### command -V
180 myfunc() { echo x; }
181
182 shopt -s expand_aliases
183 alias ll='ls -l'
184
185 backtick=\`
186 command -V ll | sed "s/$backtick/'/g"
187 echo status=$?
188
189 command -V echo
190 echo status=$?
191
192 command -V myfunc
193 echo status=$?
194
195 command -V nonexistent # doesn't print anything
196 echo status=$?
197
198 command -V for
199 echo status=$?
200
201 ## STDOUT:
202 ll is an alias for "ls -l"
203 status=0
204 echo is a shell builtin
205 status=0
206 myfunc is a shell function
207 status=0
208 status=1
209 for is a shell keyword
210 status=0
211 ## END
212
213 ## OK zsh STDOUT:
214 ll is an alias for ls -l
215 status=0
216 echo is a shell builtin
217 status=0
218 myfunc is a shell function
219 status=0
220 nonexistent not found
221 status=1
222 for is a reserved word
223 status=0
224 ## END
225
226 ## OK bash STDOUT:
227 ll is aliased to 'ls -l'
228 status=0
229 echo is a shell builtin
230 status=0
231 myfunc is a function
232 myfunc ()
233 {
234 echo x
235 }
236 status=0
237 status=1
238 for is a shell keyword
239 status=0
240 ## END
241
242 ## OK mksh STDOUT:
243 ll is an alias for 'ls -l'
244 status=0
245 echo is a shell builtin
246 status=0
247 myfunc is a function
248 status=0
249 nonexistent not found
250 status=1
251 for is a reserved word
252 status=0
253 ## END
254
255 ## OK dash STDOUT:
256 ll is an alias for ls -l
257 status=0
258 echo is a shell builtin
259 status=0
260 myfunc is a shell function
261 status=0
262 nonexistent: not found
263 status=127
264 for is a shell keyword
265 status=0
266 ## END
267
268 #### command -V nonexistent
269 command -V nonexistent 2>err.txt
270 echo status=$?
271 fgrep -o 'nonexistent: not found' err.txt || true
272
273 ## STDOUT:
274 status=1
275 nonexistent: not found
276 ## END
277
278 ## OK zsh/mksh STDOUT:
279 nonexistent not found
280 status=1
281 ## END
282
283 ## BUG dash STDOUT:
284 nonexistent: not found
285 status=127
286 ## END
287
288
289 #### command skips function lookup
290 seq() {
291 echo "$@"
292 }
293 command # no-op
294 seq 3
295 command seq 3
296 # subshell shouldn't fork another process (but we don't have a good way of
297 # testing it)
298 ( command seq 3 )
299 ## STDOUT:
300 3
301 1
302 2
303 3
304 1
305 2
306 3
307 ## END
308
309 #### command command seq 3
310 command command seq 3
311 ## STDOUT:
312 1
313 2
314 3
315 ## END
316 ## N-I zsh stdout-json: ""
317 ## N-I zsh status: 127
318
319 #### command command -v seq
320 seq() {
321 echo 3
322 }
323 command command -v seq
324 ## stdout: seq
325 ## N-I zsh stdout-json: ""
326 ## N-I zsh status: 127
327
328 #### history usage
329 history
330 echo status=$?
331 history +5 # hm bash considers this valid
332 echo status=$?
333 history -5 # invalid flag
334 echo status=$?
335 history f
336 echo status=$?
337 history too many args
338 echo status=$?
339 ## status: 0
340 ## STDOUT:
341 status=0
342 status=0
343 status=2
344 status=2
345 status=2
346 ## END
347 ## OK bash STDOUT:
348 status=0
349 status=0
350 status=2
351 status=1
352 status=1
353 ## END
354 ## BUG zsh/mksh STDOUT:
355 status=1
356 status=1
357 status=1
358 status=1
359 status=1
360 ## END
361 ## N-I dash STDOUT:
362 status=127
363 status=127
364 status=127
365 status=127
366 status=127
367 ## END
368
369 #### command -p (override existing program)
370 # Tests whether command -p overrides the path
371 # tr chosen because we need a simple non-builtin
372 mkdir -p $TMP/bin
373 echo "echo wrong" > $TMP/bin/tr
374 chmod +x $TMP/bin/tr
375 PATH="$TMP/bin:$PATH"
376 echo aaa | tr "a" "b"
377 echo aaa | command -p tr "a" "b"
378 rm $TMP/bin/tr
379 ## STDOUT:
380 wrong
381 bbb
382 ## END
383
384 #### command -p (hide tool in custom path)
385 mkdir -p $TMP/bin
386 echo "echo hello" > $TMP/bin/hello
387 chmod +x $TMP/bin/hello
388 export PATH=$TMP/bin
389 command -p hello
390 ## status: 127
391
392 #### command -p (find hidden tool in default path)
393 export PATH=''
394 command -p ls
395 ## status: 0
396
397
398 #### $(command type ls)
399 type() { echo FUNCTION; }
400 type
401 s=$(command type echo)
402 echo $s | grep builtin > /dev/null
403 echo status=$?
404 ## STDOUT:
405 FUNCTION
406 status=0
407 ## END
408 ## N-I zsh STDOUT:
409 FUNCTION
410 status=1
411 ## END
412 ## N-I mksh STDOUT:
413 status=1
414 ## END
415
416 #### builtin
417 cd () { echo "hi"; }
418 cd
419 builtin cd / && pwd
420 unset -f cd
421 ## STDOUT:
422 hi
423 /
424 ## END
425 ## N-I dash STDOUT:
426 hi
427 ## END
428
429 #### builtin ls not found
430 builtin ls
431 ## status: 1
432 ## N-I dash status: 127
433
434 #### builtin no args
435 builtin
436 ## status: 0
437 ## N-I dash status: 127
438
439 #### builtin command echo hi
440 builtin command echo hi
441 ## status: 0
442 ## stdout: hi
443 ## N-I dash status: 127
444 ## N-I dash stdout-json: ""