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 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 PATH="_tmp:$PATH"
93 touch _tmp/non-executable _tmp/executable
94 chmod +x _tmp/executable
95
96 command -v _tmp/non-executable
97 echo status=$?
98
99 command -v _tmp/executable
100 echo status=$?
101
102 ## STDOUT:
103 status=1
104 _tmp/executable
105 status=0
106 ## END
107
108 ## BUG dash/ash STDOUT:
109 _tmp/non-executable
110 status=0
111 _tmp/executable
112 status=0
113 ## END
114
115 #### command -V
116 myfunc() { echo x; }
117
118 shopt -s expand_aliases
119 alias ll='ls -l'
120
121 backtick=\`
122 command -V ll | sed "s/$backtick/'/g"
123 echo status=$?
124
125 command -V echo
126 echo status=$?
127
128 # Paper over insignificant difference
129 command -V myfunc | sed 's/shell function/function/'
130 echo status=$?
131
132 command -V nonexistent # doesn't print anything
133 echo status=$?
134
135 command -V for
136 echo status=$?
137
138 ## STDOUT:
139 ll is an alias for "ls -l"
140 status=0
141 echo is a shell builtin
142 status=0
143 myfunc is a function
144 status=0
145 status=1
146 for is a shell keyword
147 status=0
148 ## END
149
150 ## OK zsh STDOUT:
151 ll is an alias for ls -l
152 status=0
153 echo is a shell builtin
154 status=0
155 myfunc is a function
156 status=0
157 nonexistent not found
158 status=1
159 for is a reserved word
160 status=0
161 ## END
162
163 ## OK bash STDOUT:
164 ll is aliased to 'ls -l'
165 status=0
166 echo is a shell builtin
167 status=0
168 myfunc is a function
169 myfunc ()
170 {
171 echo x
172 }
173 status=0
174 status=1
175 for is a shell keyword
176 status=0
177 ## END
178
179 ## OK mksh STDOUT:
180 ll is an alias for 'ls -l'
181 status=0
182 echo is a shell builtin
183 status=0
184 myfunc is a function
185 status=0
186 nonexistent not found
187 status=1
188 for is a reserved word
189 status=0
190 ## END
191
192 ## OK dash/ash STDOUT:
193 ll is an alias for ls -l
194 status=0
195 echo is a shell builtin
196 status=0
197 myfunc is a function
198 status=0
199 nonexistent: not found
200 status=127
201 for is a shell keyword
202 status=0
203 ## END
204
205 #### command -V nonexistent
206 command -V nonexistent 2>err.txt
207 echo status=$?
208 fgrep -o 'nonexistent: not found' err.txt || true
209
210 ## STDOUT:
211 status=1
212 nonexistent: not found
213 ## END
214
215 ## OK zsh/mksh STDOUT:
216 nonexistent not found
217 status=1
218 ## END
219
220 ## BUG dash/ash STDOUT:
221 nonexistent: not found
222 status=127
223 ## END
224
225
226 #### command skips function lookup
227 seq() {
228 echo "$@"
229 }
230 command # no-op
231 seq 3
232 command seq 3
233 # subshell shouldn't fork another process (but we don't have a good way of
234 # testing it)
235 ( command seq 3 )
236 ## STDOUT:
237 3
238 1
239 2
240 3
241 1
242 2
243 3
244 ## END
245
246 #### command command seq 3
247 command command seq 3
248 ## STDOUT:
249 1
250 2
251 3
252 ## END
253 ## N-I zsh stdout-json: ""
254 ## N-I zsh status: 127
255
256 #### command command -v seq
257 seq() {
258 echo 3
259 }
260 command command -v seq
261 ## stdout: seq
262 ## N-I zsh stdout-json: ""
263 ## N-I zsh status: 127
264
265 #### command -p (override existing program)
266 # Tests whether command -p overrides the path
267 # tr chosen because we need a simple non-builtin
268 mkdir -p $TMP/bin
269 echo "echo wrong" > $TMP/bin/tr
270 chmod +x $TMP/bin/tr
271 PATH="$TMP/bin:$PATH"
272 echo aaa | tr "a" "b"
273 echo aaa | command -p tr "a" "b"
274 rm $TMP/bin/tr
275 ## STDOUT:
276 wrong
277 bbb
278 ## END
279
280 #### command -p (hide tool in custom path)
281 mkdir -p $TMP/bin
282 echo "echo hello" > $TMP/bin/hello
283 chmod +x $TMP/bin/hello
284 export PATH=$TMP/bin
285 command -p hello
286 ## status: 127
287
288 #### command -p (find hidden tool in default path)
289 export PATH=''
290 command -p ls
291 ## status: 0
292
293
294 #### $(command type ls)
295 type() { echo FUNCTION; }
296 type
297 s=$(command type echo)
298 echo $s | grep builtin > /dev/null
299 echo status=$?
300 ## STDOUT:
301 FUNCTION
302 status=0
303 ## END
304 ## N-I zsh STDOUT:
305 FUNCTION
306 status=1
307 ## END
308 ## N-I mksh STDOUT:
309 status=1
310 ## END
311
312 #### builtin
313 cd () { echo "hi"; }
314 cd
315 builtin cd / && pwd
316 unset -f cd
317 ## STDOUT:
318 hi
319 /
320 ## END
321 ## N-I dash/ash STDOUT:
322 hi
323 ## END
324
325 #### builtin ls not found
326 builtin ls
327 ## status: 1
328 ## N-I dash/ash status: 127
329
330 #### builtin usage
331
332 builtin
333 echo status=$?
334
335 builtin --
336 echo status=$?
337
338 builtin -- false
339 echo status=$?
340
341 ## STDOUT:
342 status=0
343 status=0
344 status=1
345 ## END
346
347 ## BUG zsh STDOUT:
348 status=0
349 status=1
350 status=1
351 ## END
352
353 ## N-I dash/ash STDOUT:
354 status=127
355 status=127
356 status=127
357 ## END
358
359 #### builtin command echo hi
360 builtin command echo hi
361 ## status: 0
362 ## stdout: hi
363 ## N-I dash/ash status: 127
364 ## N-I dash/ash stdout-json: ""