1 ## compare_shells: bash dash mksh zsh
2
3
4 # Alias is in POSIX.
5 #
6 # http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_03_01
7 #
8 # Bash is the only one that doesn't support aliases by default!
9
10 #### Usage of builtins
11 shopt -s expand_aliases || true
12 alias -- foo=echo
13 echo status=$?
14 foo x
15 unalias -- foo
16 foo x
17 ## status: 127
18 ## STDOUT:
19 status=0
20 x
21 ## END
22 # dash doesn't accept --
23 ## BUG dash STDOUT:
24 status=1
25 x
26 ## END
27
28 #### Basic alias
29 shopt -s expand_aliases # bash requires this
30 alias hi='echo hello world'
31 hi || echo 'should not run this'
32 echo hi # second word is not
33 'hi' || echo 'expected failure'
34 ## STDOUT:
35 hello world
36 hi
37 expected failure
38 ## END
39
40 #### define and use alias on a single line
41 shopt -s expand_aliases
42 alias e=echo; e one # this is not alias-expanded because we parse lines at once
43 e two; e three
44 ## STDOUT:
45 two
46 three
47 ## END
48
49 #### alias can override builtin
50 shopt -s expand_aliases
51 alias echo='echo foo'
52 echo bar
53 ## stdout: foo bar
54
55 #### defining multiple aliases, then unalias
56 shopt -s expand_aliases # bash requires this
57 x=x
58 y=y
59 alias echo-x='echo $x' echo-y='echo $y'
60 echo status=$?
61 echo-x X
62 echo-y Y
63 unalias echo-x echo-y
64 echo status=$?
65 echo-x X || echo undefined
66 echo-y Y || echo undefined
67 ## STDOUT:
68 status=0
69 x X
70 y Y
71 status=0
72 undefined
73 undefined
74 ## END
75
76 #### alias not defined
77 alias e='echo' nonexistentZ
78 echo status=$?
79 ## STDOUT:
80 status=1
81 ## END
82 ## OK mksh STDOUT:
83 nonexistentZ alias not found
84 status=1
85 ## END
86
87 #### unalias not defined
88 alias e=echo ll='ls -l'
89 unalias e nonexistentZ ll
90 echo status=$?
91 ## STDOUT:
92 status=1
93 ## END
94
95 #### listing given aliases
96 alias e=echo ll='ls -l'
97 alias e ll
98 ## STDOUT:
99 alias e='echo'
100 alias ll='ls -l'
101 ## END
102 ## OK mksh/zsh STDOUT:
103 e=echo
104 ll='ls -l'
105 ## END
106 ## OK dash STDOUT:
107 e='echo'
108 ll='ls -l'
109 ## END
110
111 #### alias without args lists all aliases
112 alias ex=exit ll='ls -l'
113 alias | grep -E 'ex=|ll=' # need to grep because mksh/zsh have builtin aliases
114 echo status=$?
115 ## STDOUT:
116 alias ex='exit'
117 alias ll='ls -l'
118 status=0
119 ## END
120 ## OK dash STDOUT:
121 ex='exit'
122 ll='ls -l'
123 status=0
124 ## END
125 ## OK mksh/zsh STDOUT:
126 ex=exit
127 ll='ls -l'
128 status=0
129 ## END
130
131 #### unalias without args is a usage error
132 unalias
133 echo status=$?
134 ## stdout: status=2
135 ## BUG mksh/dash stdout: status=0
136 ## BUG zsh stdout: status=1
137
138 #### alias with trailing space causes alias expansion on second word
139 shopt -s expand_aliases # bash requires this
140
141 alias hi='echo hello world '
142 alias punct='!!!'
143
144 hi punct
145
146 alias hi='echo hello world' # No trailing space
147
148 hi punct
149
150 ## STDOUT:
151 hello world !!!
152 hello world punct
153 ## END
154
155 #### Recursive alias expansion of first word
156 shopt -s expand_aliases # bash requires this
157 alias hi='e_ hello world'
158 alias e_='echo __'
159 hi # first hi is expanded to echo hello world; then echo is expanded. gah.
160 ## STDOUT:
161 __ hello world
162 ## END
163
164 #### Recursive alias expansion of SECOND word
165 shopt -s expand_aliases # bash requires this
166 alias one='ONE '
167 alias two='TWO '
168 alias e_='echo one '
169 e_ two hello world
170 ## STDOUT:
171 one TWO hello world
172 ## END
173
174 #### Expansion of alias with variable
175 shopt -s expand_aliases # bash requires this
176 x=x
177 alias echo-x='echo $x' # nothing is evaluated here
178 x=y
179 echo-x hi
180 ## STDOUT:
181 y hi
182 ## END
183
184 #### Alias must be an unquoted word, no expansions allowed
185 shopt -s expand_aliases # bash requires this
186 alias echo_alias_='echo'
187 cmd=echo_alias_
188 echo_alias_ X # this works
189 $cmd X # this fails because it's quoted
190 echo status=$?
191 ## STDOUT:
192 X
193 status=127
194 ## END
195
196 #### first and second word are the same alias, but no trailing space
197 shopt -s expand_aliases # bash requires this
198 x=x
199 alias echo-x='echo $x' # nothing is evaluated here
200 echo-x echo-x
201 ## STDOUT:
202 x echo-x
203 ## END
204
205 #### first and second word are the same alias, with trailing space
206 shopt -s expand_aliases # bash requires this
207 x=x
208 alias echo-x='echo $x ' # nothing is evaluated here
209 echo-x echo-x
210 ## STDOUT:
211 x echo x
212 ## END
213
214 #### Invalid syntax of alias
215 shopt -s expand_aliases # bash requires this
216 alias echo_alias_= 'echo --; echo' # bad space here
217 echo_alias_ x
218 ## status: 127
219
220 #### Dynamic alias definition
221 shopt -s expand_aliases # bash requires this
222 x=x
223 name='echo_alias_'
224 val='=echo'
225 alias "$name$val"
226 echo_alias_ X
227 ## stdout: X
228
229 #### Alias name with punctuation
230 # NOTE: / is not OK in bash, but OK in other shells. Must less restrictive
231 # than var names.
232 shopt -s expand_aliases # bash requires this
233 alias e_+.~x='echo'
234 e_+.~x X
235 ## stdout: X
236
237 #### Syntax error after expansion
238 shopt -s expand_aliases # bash requires this
239 alias e_=';; oops'
240 e_ x
241 ## status: 2
242 ## OK mksh/zsh status: 1
243
244 #### Loop split across alias and arg works
245 shopt -s expand_aliases # bash requires this
246 alias e_='for i in 1 2 3; do echo $i;'
247 e_ done
248 ## STDOUT:
249 1
250 2
251 3
252 ## END
253
254 #### Loop split across alias in another way
255 shopt -s expand_aliases
256 alias e_='for i in 1 2 3; do echo '
257 e_ $i; done
258 ## STDOUT:
259 1
260 2
261 3
262 ## END
263 ## OK osh stdout-json: ""
264 ## OK osh status: 2
265
266 #### Loop split across both iterative and recursive aliases
267 shopt -s expand_aliases # bash requires this
268 alias FOR1='for '
269 alias FOR2='FOR1 '
270 alias eye1='i '
271 alias eye2='eye1 '
272 alias IN='in '
273 alias onetwo='$one "2" ' # NOTE: this does NOT work in any shell except bash.
274 one=1
275 FOR2 eye2 IN onetwo 3; do echo $i; done
276 ## STDOUT:
277 1
278 2
279 3
280 ## END
281 ## OK osh stdout-json: ""
282 ## OK osh status: 2
283 ## BUG zsh stdout-json: ""
284
285 #### Alias with a quote in the middle is a syntax error
286 shopt -s expand_aliases
287 alias e_='echo "'
288 var=x
289 e_ '${var}"'
290 ## status: 2
291 ## OK mksh/zsh status: 1
292
293 #### Alias with internal newlines
294 shopt -s expand_aliases
295 alias e_='echo 1
296 echo 2
297 echo 3'
298 var='echo foo'
299 e_ ${var}
300 ## STDOUT:
301 1
302 2
303 3 echo foo
304 ## END
305
306 #### Alias trailing newline
307 shopt -s expand_aliases
308 alias e_='echo 1
309 echo 2
310 echo 3
311 '
312 var='echo foo'
313 e_ ${var}
314 ## STDOUT:
315 1
316 2
317 3
318 foo
319 ## END
320 ## OK zsh STDOUT:
321 1
322 2
323 3
324 ## END
325 ## OK zsh status: 127
326
327 #### Two aliases in pipeline
328 shopt -s expand_aliases
329 alias SEQ='seq '
330 alias THREE='3 '
331 alias WC='wc '
332 SEQ THREE | WC -l
333 ## stdout: 3
334
335 #### Alias not respected inside $()
336 # This could be parsed correctly, but it is only defined in a child process.
337 shopt -s expand_aliases
338 echo $(alias sayhi='echo hello')
339 sayhi
340 ## status: 127
341
342 #### Alias can be defined and used on a single line
343 shopt -s expand_aliases
344 alias sayhi='echo hello'; sayhi same line
345 sayhi other line
346 ## STDOUT:
347 hello other line
348 ## END
349
350 #### Alias is respected inside eval
351 shopt -s expand_aliases
352 eval "alias sayhi='echo hello'
353 sayhi inside"
354 sayhi outside
355 ## STDOUT:
356 hello inside
357 hello outside
358 ## END
359 ## BUG zsh STDOUT:
360 hello outside
361 ## END
362
363 #### alias with redirects works
364 shopt -s expand_aliases
365 alias e_=echo
366 >$TMP/alias1.txt e_ 1
367 e_ >$TMP/alias2.txt 2
368 e_ 3 >$TMP/alias3.txt
369 cat $TMP/alias1.txt $TMP/alias2.txt $TMP/alias3.txt
370 ## STDOUT:
371 1
372 2
373 3
374 ## END
375
376 #### alias with environment bindings works
377 shopt -s expand_aliases
378 alias p_=printenv.py
379 FOO=1 printenv.py FOO
380 FOO=2 p_ FOO
381 ## STDOUT:
382 1
383 2
384 ## END
385
386 #### alias with line continuation in the middle
387 shopt -s expand_aliases
388 alias e_='echo '
389 alias one='ONE '
390 alias two='TWO '
391 alias three='THREE' # no trailing space
392 e_ one \
393 two one \
394 two three two \
395 one
396 ## stdout: ONE TWO ONE TWO THREE two one
397
398 #### alias for left brace
399 shopt -s expand_aliases
400 alias LEFT='{'
401 LEFT echo one; echo two; }
402 ## STDOUT:
403 one
404 two
405 ## END
406 ## OK osh stdout-json: ""
407 ## OK osh status: 2
408
409 #### alias for left paren
410 shopt -s expand_aliases
411 alias LEFT='('
412 LEFT echo one; echo two )
413 ## STDOUT:
414 one
415 two
416 ## END
417 ## OK osh stdout-json: ""
418 ## OK osh status: 2
419
420 #### alias used in subshell and command sub
421 # This spec seems to be contradictoary?
422 # http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_03_01
423 # "When used as specified by this volume of POSIX.1-2017, alias definitions
424 # shall not be inherited by separate invocations of the shell or by the utility
425 # execution environments invoked by the shell; see Shell Execution
426 # Environment."
427 shopt -s expand_aliases
428 alias echo_='echo [ '
429 ( echo_ subshell; )
430 echo $(echo_ commandsub)
431 ## STDOUT:
432 [ subshell
433 [ commandsub
434 ## END
435
436 #### alias used in here doc
437 shopt -s expand_aliases
438 alias echo_='echo [ '
439 cat <<EOF
440 $(echo_ ])
441 EOF
442 ## STDOUT:
443 [ ]
444 ## END
445
446 #### here doc inside alias
447 shopt -s expand_aliases
448 alias c='cat <<EOF
449 $(echo hi)
450 EOF
451 '
452 c
453 ## STDOUT:
454 hi
455 ## END
456 ## BUG bash stdout-json: ""
457 ## BUG bash status: 127
458
459 #### Corner case: alias inside LHS array arithmetic expression
460 shopt -s expand_aliases
461 alias zero='echo 0'
462 a[$(zero)]=ZERO
463 a[1]=ONE
464 argv.py "${a[@]}"
465 ## STDOUT:
466 ['ZERO', 'ONE']
467 ## END
468 ## N-I dash stdout-json: ""
469 ## N-I dash status: 2
470 ## N-I zsh stdout-json: ""
471 ## N-I zsh status: 1
472
473 #### Alias that is pipeline
474 shopt -s expand_aliases
475 alias t1='echo hi|wc -c'
476 t1
477 ## STDOUT:
478 3
479 ## END
480
481 #### Alias that is && || ;
482 shopt -s expand_aliases
483 alias t1='echo one && echo two && echo 3 | wc -l;
484 echo four'
485 t1
486 ## STDOUT:
487 one
488 two
489 1
490 four
491 ## END
492
493 #### Alias and command sub (bug regression)
494 cd $TMP
495 shopt -s expand_aliases
496 echo foo bar > tmp.txt
497 alias a=argv.py
498 a `cat tmp.txt`
499 ## stdout: ['foo', 'bar']
500
501 #### Alias and arithmetic
502 shopt -s expand_aliases
503 alias a=argv.py
504 a $((1 + 2))
505 ## stdout: ['3']
506
507 #### Alias and PS4
508 # dash enters an infinite loop!
509 case $SH in
510 dash)
511 exit 1
512 ;;
513 esac
514
515 set -x
516 PS4='+$(echo trace) '
517 shopt -s expand_aliases
518 alias a=argv.py
519 a foo bar
520 ## stdout: ['foo', 'bar']
521 ## BUG dash status: 1
522 ## BUG dash stdout-json: ""
523
524 #### alias with keywords
525 # from issue #299
526 shopt -s expand_aliases
527 alias a=
528
529 # both of these fail to parse in OSH
530 # this is because of our cleaner evaluation model
531
532 a (( var = 0 ))
533 #a case x in x) true;; esac
534
535 echo done
536 ## stdout: done
537 ## OK osh status: 2
538 ## OK osh stdout-json: ""
539
540
541 #### alias with word of multiple lines
542 shopt -s expand_aliases
543
544 alias ll='ls -l'
545 ll '1
546 2
547 3'
548 echo status=$?
549
550 ## STDOUT:
551 status=2
552 ## END