1 ## oils_failures_allowed: 1
2 ## compare_shells: dash bash mksh zsh
3
4 #### command -v
5 myfunc() { echo x; }
6 command -v echo
7 echo $?
8
9 command -v myfunc
10 echo $?
11
12 command -v nonexistent # doesn't print anything
13 echo nonexistent=$?
14
15 command -v '' # BUG FIX, shouldn't succeed
16 echo empty=$?
17
18 command -v for
19 echo $?
20
21 ## STDOUT:
22 echo
23 0
24 myfunc
25 0
26 nonexistent=1
27 empty=1
28 for
29 0
30 ## OK dash STDOUT:
31 echo
32 0
33 myfunc
34 0
35 nonexistent=127
36 empty=127
37 for
38 0
39 ## END
40
41 #### command -v executable
42
43 #command -v grep ls
44
45 command -v grep | egrep -o '/[^/]+$'
46 command -v ls | egrep -o '/[^/]+$'
47
48 ## STDOUT:
49 /grep
50 /ls
51 ## END
52
53
54 #### command -v with multiple names
55 # ALL FOUR SHELLS behave differently here!
56 #
57 # bash chooses to swallow the error! We agree with zsh if ANY word lookup
58 # fails, then the whole thing fails.
59
60 myfunc() { echo x; }
61 command -v echo myfunc ZZZ for
62 echo status=$?
63
64 ## STDOUT:
65 echo
66 myfunc
67 for
68 status=1
69 ## BUG bash STDOUT:
70 echo
71 myfunc
72 for
73 status=0
74 ## BUG dash STDOUT:
75 echo
76 status=0
77 ## OK mksh STDOUT:
78 echo
79 myfunc
80 status=1
81 ## END
82
83 #### command -v doesn't find non-executable file
84 # PATH resolution is different
85
86 PATH="_tmp:$PATH"
87 touch _tmp/non-executable _tmp/executable
88 chmod +x _tmp/executable
89
90 command -v _tmp/non-executable
91 echo status=$?
92
93 command -v _tmp/executable
94 echo status=$?
95
96 ## STDOUT:
97 status=1
98 _tmp/executable
99 status=0
100 ## END
101
102 ## BUG dash STDOUT:
103 _tmp/non-executable
104 status=0
105 _tmp/executable
106 status=0
107 ## END
108
109 #### command -V
110 myfunc() { echo x; }
111
112 shopt -s expand_aliases
113 alias ll='ls -l'
114
115 backtick=\`
116 command -V ll | sed "s/$backtick/'/g"
117 echo status=$?
118
119 command -V echo
120 echo status=$?
121
122 command -V myfunc
123 echo status=$?
124
125 command -V nonexistent # doesn't print anything
126 echo status=$?
127
128 command -V for
129 echo status=$?
130
131 ## STDOUT:
132 ll is an alias for "ls -l"
133 status=0
134 echo is a shell builtin
135 status=0
136 myfunc is a shell function
137 status=0
138 status=1
139 for is a shell keyword
140 status=0
141 ## END
142
143 ## OK zsh STDOUT:
144 ll is an alias for ls -l
145 status=0
146 echo is a shell builtin
147 status=0
148 myfunc is a shell function
149 status=0
150 nonexistent not found
151 status=1
152 for is a reserved word
153 status=0
154 ## END
155
156 ## OK bash STDOUT:
157 ll is aliased to 'ls -l'
158 status=0
159 echo is a shell builtin
160 status=0
161 myfunc is a function
162 myfunc ()
163 {
164 echo x
165 }
166 status=0
167 status=1
168 for is a shell keyword
169 status=0
170 ## END
171
172 ## OK mksh STDOUT:
173 ll is an alias for 'ls -l'
174 status=0
175 echo is a shell builtin
176 status=0
177 myfunc is a function
178 status=0
179 nonexistent not found
180 status=1
181 for is a reserved word
182 status=0
183 ## END
184
185 ## OK dash STDOUT:
186 ll is an alias for ls -l
187 status=0
188 echo is a shell builtin
189 status=0
190 myfunc is a shell function
191 status=0
192 nonexistent: not found
193 status=127
194 for is a shell keyword
195 status=0
196 ## END
197
198 #### command -V nonexistent
199 command -V nonexistent 2>err.txt
200 echo status=$?
201 fgrep -o 'nonexistent: not found' err.txt || true
202
203 ## STDOUT:
204 status=1
205 nonexistent: not found
206 ## END
207
208 ## OK zsh/mksh STDOUT:
209 nonexistent not found
210 status=1
211 ## END
212
213 ## BUG dash STDOUT:
214 nonexistent: not found
215 status=127
216 ## END
217
218
219 #### command skips function lookup
220 seq() {
221 echo "$@"
222 }
223 command # no-op
224 seq 3
225 command seq 3
226 # subshell shouldn't fork another process (but we don't have a good way of
227 # testing it)
228 ( command seq 3 )
229 ## STDOUT:
230 3
231 1
232 2
233 3
234 1
235 2
236 3
237 ## END
238
239 #### command command seq 3
240 command command seq 3
241 ## STDOUT:
242 1
243 2
244 3
245 ## END
246 ## N-I zsh stdout-json: ""
247 ## N-I zsh status: 127
248
249 #### command command -v seq
250 seq() {
251 echo 3
252 }
253 command command -v seq
254 ## stdout: seq
255 ## N-I zsh stdout-json: ""
256 ## N-I zsh status: 127
257
258 #### command -p (override existing program)
259 # Tests whether command -p overrides the path
260 # tr chosen because we need a simple non-builtin
261 mkdir -p $TMP/bin
262 echo "echo wrong" > $TMP/bin/tr
263 chmod +x $TMP/bin/tr
264 PATH="$TMP/bin:$PATH"
265 echo aaa | tr "a" "b"
266 echo aaa | command -p tr "a" "b"
267 rm $TMP/bin/tr
268 ## STDOUT:
269 wrong
270 bbb
271 ## END
272
273 #### command -p (hide tool in custom path)
274 mkdir -p $TMP/bin
275 echo "echo hello" > $TMP/bin/hello
276 chmod +x $TMP/bin/hello
277 export PATH=$TMP/bin
278 command -p hello
279 ## status: 127
280
281 #### command -p (find hidden tool in default path)
282 export PATH=''
283 command -p ls
284 ## status: 0
285
286
287 #### $(command type ls)
288 type() { echo FUNCTION; }
289 type
290 s=$(command type echo)
291 echo $s | grep builtin > /dev/null
292 echo status=$?
293 ## STDOUT:
294 FUNCTION
295 status=0
296 ## END
297 ## N-I zsh STDOUT:
298 FUNCTION
299 status=1
300 ## END
301 ## N-I mksh STDOUT:
302 status=1
303 ## END
304
305 #### builtin
306 cd () { echo "hi"; }
307 cd
308 builtin cd / && pwd
309 unset -f cd
310 ## STDOUT:
311 hi
312 /
313 ## END
314 ## N-I dash STDOUT:
315 hi
316 ## END
317
318 #### builtin ls not found
319 builtin ls
320 ## status: 1
321 ## N-I dash status: 127
322
323 #### builtin no args
324 builtin
325 ## status: 0
326 ## N-I dash status: 127
327
328 #### builtin command echo hi
329 builtin command echo hi
330 ## status: 0
331 ## stdout: hi
332 ## N-I dash status: 127
333 ## N-I dash stdout-json: ""
334
335 #### builtin typeset / export / readonly
336 case $SH in dash) exit ;; esac
337
338 builtin typeset s=typeset
339 echo s=$s
340
341 builtin export s=export
342 echo s=$s
343
344 builtin readonly s=readonly
345 echo s=$s
346
347 echo --
348
349 builtin builtin typeset s2=typeset
350 echo s2=$s2
351
352 builtin builtin export s2=export
353 echo s2=$s2
354
355 builtin builtin readonly s2=readonly
356 echo s2=$s2
357
358 ## STDOUT:
359 s=typeset
360 s=export
361 s=readonly
362 --
363 s2=typeset
364 s2=export
365 s2=readonly
366 ## END
367 ## N-I dash STDOUT:
368 ## END
369
370 #### builtin declare / local
371 case $SH in dash|mksh) exit ;; esac
372
373 builtin declare s=declare
374 echo s=$s
375
376 f() {
377 builtin local s=local
378 echo s=$s
379 }
380
381 f
382
383 ## STDOUT:
384 s=declare
385 s=local
386 ## END
387 ## N-I dash/mksh STDOUT:
388 ## END
389
390 #### builtin declare a=(x y) etc.
391
392 $SH -c 'builtin declare a=(x y)'
393 if test $? -ne 0; then
394 echo 'fail'
395 fi
396
397 $SH -c 'builtin declare -a a=(x y)'
398 if test $? -ne 0; then
399 echo 'fail'
400 fi
401
402 ## STDOUT:
403 fail
404 fail
405 ## END
406
407 ## OK osh STDOUT:
408 ## END
409
410
411 #### command export / readonly
412 case $SH in zsh) exit ;; esac
413
414 # dash doesn't have declare typeset
415
416 command export c=export
417 echo c=$c
418
419 command readonly c=readonly
420 echo c=$c
421
422 echo --
423
424 command command export cc=export
425 echo cc=$cc
426
427 command command readonly cc=readonly
428 echo cc=$cc
429
430 ## STDOUT:
431 c=export
432 c=readonly
433 --
434 cc=export
435 cc=readonly
436 ## END
437 ## N-I zsh STDOUT:
438 ## END
439
440 #### command local
441
442 f() {
443 command local s=local
444 echo s=$s
445 }
446
447 f
448
449 ## STDOUT:
450 s=local
451 ## END
452 ## BUG dash/mksh/zsh STDOUT:
453 s=
454 ## END
455
456
457 #### static builtin command ASSIGN, command builtin ASSIGN
458 case $SH in dash|zsh) exit ;; esac
459
460 # dash doesn't have declare typeset
461
462 builtin command export bc=export
463 echo bc=$bc
464
465 builtin command readonly bc=readonly
466 echo bc=$bc
467
468 echo --
469
470 command builtin export cb=export
471 echo cb=$cb
472
473 command builtin readonly cb=readonly
474 echo cb=$cb
475
476 ## STDOUT:
477 bc=export
478 bc=readonly
479 --
480 cb=export
481 cb=readonly
482 ## END
483 ## N-I dash/zsh STDOUT:
484 ## END
485
486 #### dynamic builtin command ASSIGN, command builtin ASSIGN
487 case $SH in dash|zsh) exit ;; esac
488
489 b=builtin
490 c=command
491 e=export
492 r=readonly
493
494 $b $c export bc=export
495 echo bc=$bc
496
497 $b $c readonly bc=readonly
498 echo bc=$bc
499
500 echo --
501
502 $c $b export cb=export
503 echo cb=$cb
504
505 $c $b readonly cb=readonly
506 echo cb=$cb
507
508 echo --
509
510 $b $c $e bce=export
511 echo bce=$bce
512
513 $b $c $r bcr=readonly
514 echo bcr=$bcr
515
516 echo --
517
518 $c $b $e cbe=export
519 echo cbe=$cbe
520
521 $c $b $r cbr=readonly
522 echo cbr=$cbr
523
524 ## STDOUT:
525 bc=export
526 bc=readonly
527 --
528 cb=export
529 cb=readonly
530 --
531 bce=export
532 bcr=readonly
533 --
534 cbe=export
535 cbr=readonly
536 ## END
537 ## N-I dash/zsh STDOUT:
538 ## END
539
540
541 #### Assignment builtins and word splitting, even after builtin/command
542
543 x='a b'
544
545 readonly y=$x
546 echo $x
547
548 command readonly z=$x
549 echo $z
550
551 ## STDOUT:
552 a b
553 a b
554 ## END
555
556 ## BUG dash/bash STDOUT:
557 a b
558 a
559 ## END
560
561 ## N-I zsh STDOUT:
562 a b
563
564 ## END
565
566 #### More word splitting
567
568 x='a b'
569
570 export y=$x
571 echo $y
572
573 builtin export z=$x
574 echo $z
575
576 ## STDOUT:
577 a b
578 a b
579 ## END
580
581 ## BUG bash/mksh STDOUT:
582 a b
583 a
584 ## END
585
586 ## N-I dash STDOUT:
587 a
588
589 ## END
590
591 #### \builtin declare - ble.sh relies on it
592
593 # \command readonly is equivalent to \builtin declare
594 # except dash implements it
595
596 x='a b'
597
598 command readonly y=$x
599 echo $y
600
601 \command readonly z=$x
602 echo $z
603
604 # The issue here is that we have a heuristic in EvalWordSequence2:
605 # fs len(part_vals) == 1
606
607 ## STDOUT:
608 a b
609 a b
610 ## END
611
612 ## OK bash/dash STDOUT:
613 a
614 a
615 ## END
616
617 ## N-I zsh STDOUT:
618
619
620 ## END