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