1 ## compare_shells: dash bash mksh zsh ash
2
3 #### command -v
4 myfunc() { echo x; }
5 command -v echo
6 echo $?
7
8 command -v myfunc
9 echo $?
10
11 command -v nonexistent # doesn't print anything
12 echo nonexistent=$?
13
14 command -v '' # BUG FIX, shouldn't succeed
15 echo empty=$?
16
17 command -v for
18 echo $?
19
20 ## STDOUT:
21 echo
22 0
23 myfunc
24 0
25 nonexistent=1
26 empty=1
27 for
28 0
29 ## OK dash/ash STDOUT:
30 echo
31 0
32 myfunc
33 0
34 nonexistent=127
35 empty=127
36 for
37 0
38 ## END
39
40 #### command -v executable, builtin
41
42 #command -v grep ls
43
44 command -v grep | egrep -o '/[^/]+$'
45 command -v ls | egrep -o '/[^/]+$'
46 echo
47
48 command -v true
49 command -v eval
50
51 ## STDOUT:
52 /grep
53 /ls
54
55 true
56 eval
57 ## END
58
59
60 #### command -v with multiple names
61 # ALL FOUR SHELLS behave differently here!
62 #
63 # bash chooses to swallow the error! We agree with zsh if ANY word lookup
64 # fails, then the whole thing fails.
65
66 myfunc() { echo x; }
67 command -v echo myfunc ZZZ for
68 echo status=$?
69
70 ## STDOUT:
71 echo
72 myfunc
73 for
74 status=1
75 ## BUG bash STDOUT:
76 echo
77 myfunc
78 for
79 status=0
80 ## BUG-2 dash/ash STDOUT:
81 echo
82 status=0
83 ## OK mksh STDOUT:
84 echo
85 myfunc
86 status=1
87 ## END
88
89 #### command -v doesn't find non-executable file
90 # PATH resolution is different
91
92 mkdir -p _tmp
93 PATH="_tmp:$PATH"
94 touch _tmp/non-executable _tmp/executable
95 chmod +x _tmp/executable
96
97 command -v _tmp/non-executable
98 echo status=$?
99
100 command -v _tmp/executable
101 echo status=$?
102
103 ## STDOUT:
104 status=1
105 _tmp/executable
106 status=0
107 ## END
108
109 ## BUG dash/ash STDOUT:
110 _tmp/non-executable
111 status=0
112 _tmp/executable
113 status=0
114 ## END
115
116 #### command -v doesn't find executable dir
117
118 mkdir -p _tmp
119 PATH="_tmp:$PATH"
120 mkdir _tmp/cat
121
122 command -v _tmp/cat
123 echo status=$?
124 command -v cat
125 echo status=$?
126
127 ## STDOUT:
128 status=1
129 /usr/bin/cat
130 status=0
131 ## END
132
133 ## BUG mksh STDOUT:
134 status=1
135 cat
136 status=0
137 ## END
138
139 ## BUG ash/dash STDOUT:
140 _tmp/cat
141 status=0
142 /usr/bin/cat
143 status=0
144 ## END
145
146 #### command -V
147 myfunc() { echo x; }
148
149 shopt -s expand_aliases
150 alias ll='ls -l'
151
152 backtick=\`
153 command -V ll | sed "s/$backtick/'/g"
154 echo status=$?
155
156 command -V echo
157 echo status=$?
158
159 # Paper over insignificant difference
160 command -V myfunc | sed 's/shell function/function/'
161 echo status=$?
162
163 command -V nonexistent # doesn't print anything
164 echo status=$?
165
166 command -V for
167 echo status=$?
168
169 ## STDOUT:
170 ll is an alias for "ls -l"
171 status=0
172 echo is a shell builtin
173 status=0
174 myfunc is a function
175 status=0
176 status=1
177 for is a shell keyword
178 status=0
179 ## END
180
181 ## OK zsh STDOUT:
182 ll is an alias for ls -l
183 status=0
184 echo is a shell builtin
185 status=0
186 myfunc is a function
187 status=0
188 nonexistent not found
189 status=1
190 for is a reserved word
191 status=0
192 ## END
193
194 ## OK bash STDOUT:
195 ll is aliased to 'ls -l'
196 status=0
197 echo is a shell builtin
198 status=0
199 myfunc is a function
200 myfunc ()
201 {
202 echo x
203 }
204 status=0
205 status=1
206 for is a shell keyword
207 status=0
208 ## END
209
210 ## OK mksh STDOUT:
211 ll is an alias for 'ls -l'
212 status=0
213 echo is a shell builtin
214 status=0
215 myfunc is a function
216 status=0
217 nonexistent not found
218 status=1
219 for is a reserved word
220 status=0
221 ## END
222
223 ## OK dash/ash STDOUT:
224 ll is an alias for ls -l
225 status=0
226 echo is a shell builtin
227 status=0
228 myfunc is a function
229 status=0
230 nonexistent: not found
231 status=127
232 for is a shell keyword
233 status=0
234 ## END
235
236 #### command -V nonexistent
237 command -V nonexistent 2>err.txt
238 echo status=$?
239 fgrep -o 'nonexistent: not found' err.txt || true
240
241 ## STDOUT:
242 status=1
243 nonexistent: not found
244 ## END
245
246 ## OK zsh/mksh STDOUT:
247 nonexistent not found
248 status=1
249 ## END
250
251 ## BUG dash/ash STDOUT:
252 nonexistent: not found
253 status=127
254 ## END
255
256
257 #### command skips function lookup
258 seq() {
259 echo "$@"
260 }
261 command # no-op
262 seq 3
263 command seq 3
264 # subshell shouldn't fork another process (but we don't have a good way of
265 # testing it)
266 ( command seq 3 )
267 ## STDOUT:
268 3
269 1
270 2
271 3
272 1
273 2
274 3
275 ## END
276
277 #### command command seq 3
278 command command seq 3
279 ## STDOUT:
280 1
281 2
282 3
283 ## END
284 ## N-I zsh stdout-json: ""
285 ## N-I zsh status: 127
286
287 #### command command -v seq
288 seq() {
289 echo 3
290 }
291 command command -v seq
292 ## stdout: seq
293 ## N-I zsh stdout-json: ""
294 ## N-I zsh status: 127
295
296 #### command -p (override existing program)
297 # Tests whether command -p overrides the path
298 # tr chosen because we need a simple non-builtin
299 mkdir -p $TMP/bin
300 echo "echo wrong" > $TMP/bin/tr
301 chmod +x $TMP/bin/tr
302 PATH="$TMP/bin:$PATH"
303 echo aaa | tr "a" "b"
304 echo aaa | command -p tr "a" "b"
305 rm $TMP/bin/tr
306 ## STDOUT:
307 wrong
308 bbb
309 ## END
310
311 #### command -p (hide tool in custom path)
312 mkdir -p $TMP/bin
313 echo "echo hello" > $TMP/bin/hello
314 chmod +x $TMP/bin/hello
315 export PATH=$TMP/bin
316 command -p hello
317 ## status: 127
318
319 #### command -p (find hidden tool in default path)
320 export PATH=''
321 command -p ls
322 ## status: 0
323
324
325 #### $(command type ls)
326 type() { echo FUNCTION; }
327 type
328 s=$(command type echo)
329 echo $s | grep builtin > /dev/null
330 echo status=$?
331 ## STDOUT:
332 FUNCTION
333 status=0
334 ## END
335 ## N-I zsh STDOUT:
336 FUNCTION
337 status=1
338 ## END
339 ## N-I mksh STDOUT:
340 status=1
341 ## END
342
343 #### builtin
344 cd () { echo "hi"; }
345 cd
346 builtin cd / && pwd
347 unset -f cd
348 ## STDOUT:
349 hi
350 /
351 ## END
352 ## N-I dash/ash STDOUT:
353 hi
354 ## END
355
356 #### builtin ls not found
357 builtin ls
358 ## status: 1
359 ## N-I dash/ash status: 127
360
361 #### builtin usage
362
363 builtin
364 echo status=$?
365
366 builtin --
367 echo status=$?
368
369 builtin -- false
370 echo status=$?
371
372 ## STDOUT:
373 status=0
374 status=0
375 status=1
376 ## END
377
378 ## BUG zsh STDOUT:
379 status=0
380 status=1
381 status=1
382 ## END
383
384 ## N-I dash/ash STDOUT:
385 status=127
386 status=127
387 status=127
388 ## END
389
390 #### builtin command echo hi
391 builtin command echo hi
392 ## status: 0
393 ## stdout: hi
394 ## N-I dash/ash status: 127
395 ## N-I dash/ash stdout-json: ""