1 | ## oils_failures_allowed: 1
|
2 | ## compare_shells: dash bash mksh
|
3 |
|
4 | #### zero args: [ ]
|
5 | [ ] || echo false
|
6 | ## stdout: false
|
7 |
|
8 | #### one arg: [ x ] where x is one of '=' '!' '(' ']'
|
9 | [ = ]
|
10 | echo status=$?
|
11 | [ ] ]
|
12 | echo status=$?
|
13 | [ '!' ]
|
14 | echo status=$?
|
15 | [ '(' ]
|
16 | echo status=$?
|
17 | ## STDOUT:
|
18 | status=0
|
19 | status=0
|
20 | status=0
|
21 | status=0
|
22 | ## END
|
23 |
|
24 | #### one arg: empty string is false. Equivalent to -n.
|
25 | test 'a' && echo true
|
26 | test '' || echo false
|
27 | ## STDOUT:
|
28 | true
|
29 | false
|
30 | ## END
|
31 |
|
32 | #### -a as unary operator (alias of -e)
|
33 | # NOT IMPLEMENTED FOR OSH, but could be later. See comment in core/id_kind.py.
|
34 | [ -a / ]
|
35 | echo status=$?
|
36 | [ -a /nonexistent ]
|
37 | echo status=$?
|
38 | ## STDOUT:
|
39 | status=0
|
40 | status=1
|
41 | ## END
|
42 | ## N-I dash STDOUT:
|
43 | status=2
|
44 | status=2
|
45 | ## END
|
46 |
|
47 | #### two args: -z with = ! ( ]
|
48 | [ -z = ]
|
49 | echo status=$?
|
50 | [ -z ] ]
|
51 | echo status=$?
|
52 | [ -z '!' ]
|
53 | echo status=$?
|
54 | [ -z '(' ]
|
55 | echo status=$?
|
56 | ## STDOUT:
|
57 | status=1
|
58 | status=1
|
59 | status=1
|
60 | status=1
|
61 | ## END
|
62 |
|
63 | #### three args
|
64 | [ foo = '' ]
|
65 | echo status=$?
|
66 | [ foo -a '' ]
|
67 | echo status=$?
|
68 | [ foo -o '' ]
|
69 | echo status=$?
|
70 | [ ! -z foo ]
|
71 | echo status=$?
|
72 | [ \( foo \) ]
|
73 | echo status=$?
|
74 | ## STDOUT:
|
75 | status=1
|
76 | status=1
|
77 | status=0
|
78 | status=0
|
79 | status=0
|
80 | ## END
|
81 |
|
82 | #### four args
|
83 | [ ! foo = foo ]
|
84 | echo status=$?
|
85 | [ \( -z foo \) ]
|
86 | echo status=$?
|
87 | ## STDOUT:
|
88 | status=1
|
89 | status=1
|
90 | ## END
|
91 |
|
92 | #### test with extra args is syntax error
|
93 | test -n x ]
|
94 | echo status=$?
|
95 | test -n x y
|
96 | echo status=$?
|
97 | ## STDOUT:
|
98 | status=2
|
99 | status=2
|
100 | ## END
|
101 |
|
102 | #### ] syntax errors
|
103 | [
|
104 | echo status=$?
|
105 | test # not a syntax error
|
106 | echo status=$?
|
107 | [ -n x # missing ]
|
108 | echo status=$?
|
109 | [ -n x ] y # extra arg after ]
|
110 | echo status=$?
|
111 | [ -n x y # extra arg
|
112 | echo status=$?
|
113 | ## STDOUT:
|
114 | status=2
|
115 | status=1
|
116 | status=2
|
117 | status=2
|
118 | status=2
|
119 | ## END
|
120 |
|
121 | #### -n
|
122 | test -n 'a' && echo true
|
123 | test -n '' || echo false
|
124 | ## STDOUT:
|
125 | true
|
126 | false
|
127 | ## END
|
128 |
|
129 | #### ! -a
|
130 | [ -z '' -a ! -z x ]
|
131 | echo status=$?
|
132 | ## stdout: status=0
|
133 |
|
134 | #### -o
|
135 | [ -z x -o ! -z x ]
|
136 | echo status=$?
|
137 | ## stdout: status=0
|
138 |
|
139 | #### ( )
|
140 | [ -z '' -a '(' ! -z x ')' ]
|
141 | echo status=$?
|
142 | ## stdout: status=0
|
143 |
|
144 | #### ( ) ! -a -o with system version of [
|
145 | command [ --version
|
146 | command [ -z '' -a '(' ! -z x ')' ] && echo true
|
147 | ## stdout: true
|
148 |
|
149 | #### == is alias for =
|
150 | [ a = a ] && echo true
|
151 | [ a == a ] && echo true
|
152 | ## STDOUT:
|
153 | true
|
154 | true
|
155 | ## END
|
156 | ## BUG dash STDOUT:
|
157 | true
|
158 | ## END
|
159 | ## BUG dash status: 2
|
160 |
|
161 | #### == and = does not do glob
|
162 | [ abc = 'a*' ]
|
163 | echo status=$?
|
164 | [ abc == 'a*' ]
|
165 | echo status=$?
|
166 | ## STDOUT:
|
167 | status=1
|
168 | status=1
|
169 | ## END
|
170 | ## N-I dash STDOUT:
|
171 | status=1
|
172 | status=2
|
173 | ## END
|
174 |
|
175 | #### [ with op variable
|
176 | # OK -- parsed AFTER evaluation of vars
|
177 | op='='
|
178 | [ a $op a ] && echo true
|
179 | [ a $op b ] || echo false
|
180 | ## status: 0
|
181 | ## STDOUT:
|
182 | true
|
183 | false
|
184 | ## END
|
185 |
|
186 | #### [ with unquoted empty var
|
187 | empty=''
|
188 | [ $empty = '' ] && echo true
|
189 | ## status: 2
|
190 |
|
191 | #### [ compare with literal -f
|
192 | # Hm this is the same
|
193 | var=-f
|
194 | [ $var = -f ] && echo true
|
195 | [ '-f' = $var ] && echo true
|
196 | ## STDOUT:
|
197 | true
|
198 | true
|
199 | ## END
|
200 |
|
201 | #### [ '(' foo ] is runtime syntax error
|
202 | [ '(' foo ]
|
203 | echo status=$?
|
204 | ## stdout: status=2
|
205 |
|
206 | #### -z '>' implies two token lookahead
|
207 | [ -z ] && echo true # -z is operand
|
208 | [ -z '>' ] || echo false # -z is operator
|
209 | [ -z '>' -- ] && echo true # -z is operand
|
210 | ## STDOUT:
|
211 | true
|
212 | false
|
213 | true
|
214 | ## END
|
215 |
|
216 | #### operator/operand ambiguity with ]
|
217 | # bash parses this as '-z' AND ']', which is true. It's a syntax error in
|
218 | # dash/mksh.
|
219 | [ -z -a ] ]
|
220 | echo status=$?
|
221 | ## stdout: status=0
|
222 | ## OK mksh stdout: status=2
|
223 | ## OK dash stdout: status=2
|
224 |
|
225 | #### operator/operand ambiguity with -a
|
226 | # bash parses it as '-z' AND '-a'. It's a syntax error in mksh but somehow a
|
227 | # runtime error in dash.
|
228 | [ -z -a -a ]
|
229 | echo status=$?
|
230 | ## stdout: status=0
|
231 | ## OK mksh stdout: status=2
|
232 | ## OK dash stdout: status=1
|
233 |
|
234 | #### -d
|
235 | test -d $TMP
|
236 | echo status=$?
|
237 | test -d $TMP/__nonexistent_Z_Z__
|
238 | echo status=$?
|
239 | ## STDOUT:
|
240 | status=0
|
241 | status=1
|
242 | ## END
|
243 |
|
244 | #### -x
|
245 | rm -f $TMP/x
|
246 | echo 'echo hi' > $TMP/x
|
247 | test -x $TMP/x || echo 'no'
|
248 | chmod +x $TMP/x
|
249 | test -x $TMP/x && echo 'yes'
|
250 | test -x $TMP/__nonexistent__ || echo 'bad'
|
251 | ## STDOUT:
|
252 | no
|
253 | yes
|
254 | bad
|
255 | ## END
|
256 |
|
257 | #### -r
|
258 | echo '1' > $TMP/testr_yes
|
259 | echo '2' > $TMP/testr_no
|
260 | chmod -r $TMP/testr_no # remove read permission
|
261 | test -r $TMP/testr_yes && echo 'yes'
|
262 | test -r $TMP/testr_no || echo 'no'
|
263 | ## STDOUT:
|
264 | yes
|
265 | no
|
266 | ## END
|
267 |
|
268 | #### -w
|
269 | rm -f $TMP/testw_*
|
270 | echo '1' > $TMP/testw_yes
|
271 | echo '2' > $TMP/testw_no
|
272 | chmod -w $TMP/testw_no # remove write permission
|
273 | test -w $TMP/testw_yes && echo 'yes'
|
274 | test -w $TMP/testw_no || echo 'no'
|
275 | ## STDOUT:
|
276 | yes
|
277 | no
|
278 | ## END
|
279 |
|
280 | #### -k for sticky bit
|
281 | # not isolated: /tmp usually has sticky bit on
|
282 | # https://en.wikipedia.org/wiki/Sticky_bit
|
283 |
|
284 | test -k /tmp
|
285 | echo status=$?
|
286 |
|
287 | test -k /bin
|
288 | echo status=$?
|
289 | ## STDOUT:
|
290 | status=0
|
291 | status=1
|
292 | ## END
|
293 |
|
294 | #### -h and -L test for symlink
|
295 | tmp=$TMP/builtin-test-1
|
296 | mkdir -p $tmp
|
297 | touch $tmp/zz
|
298 | ln -s -f $tmp/zz $tmp/symlink
|
299 | ln -s -f $tmp/__nonexistent_ZZ__ $tmp/dangling
|
300 | test -L $tmp/zz || echo no
|
301 | test -h $tmp/zz || echo no
|
302 | test -f $tmp/symlink && echo is-file
|
303 | test -L $tmp/symlink && echo symlink
|
304 | test -h $tmp/symlink && echo symlink
|
305 | test -L $tmp/dangling && echo dangling
|
306 | test -h $tmp/dangling && echo dangling
|
307 | test -f $tmp/dangling || echo 'dangling is not file'
|
308 | ## STDOUT:
|
309 | no
|
310 | no
|
311 | is-file
|
312 | symlink
|
313 | symlink
|
314 | dangling
|
315 | dangling
|
316 | dangling is not file
|
317 | ## END
|
318 |
|
319 | #### -t 1 for stdout
|
320 | # There is no way to get a terminal in the test environment?
|
321 | [ -t 1 ]
|
322 | echo status=$?
|
323 | ## stdout: status=1
|
324 |
|
325 | #### [ -t invalid ]
|
326 | [ -t invalid ]
|
327 | echo status=$?
|
328 | ## stdout: status=2
|
329 | ## BUG bash stdout: status=1
|
330 |
|
331 | #### -ot and -nt
|
332 | touch -d 2017/12/31 $TMP/x
|
333 | touch -d 2018/01/01 > $TMP/y
|
334 | test $TMP/x -ot $TMP/y && echo 'older'
|
335 | test $TMP/x -nt $TMP/y || echo 'not newer'
|
336 | test $TMP/x -ot $TMP/x || echo 'not older than itself'
|
337 | test $TMP/x -nt $TMP/x || echo 'not newer than itself'
|
338 | ## STDOUT:
|
339 | older
|
340 | not newer
|
341 | not older than itself
|
342 | not newer than itself
|
343 | ## END
|
344 |
|
345 | #### [ a -eq b ]
|
346 | [ a -eq a ]
|
347 | echo status=$?
|
348 | ## STDOUT:
|
349 | status=2
|
350 | ## END
|
351 | ## BUG mksh STDOUT:
|
352 | status=0
|
353 | ## END
|
354 |
|
355 | #### test -s
|
356 | test -s __nonexistent
|
357 | echo status=$?
|
358 | touch $TMP/empty
|
359 | test -s $TMP/empty
|
360 | echo status=$?
|
361 | echo nonempty > $TMP/nonempty
|
362 | test -s $TMP/nonempty
|
363 | echo status=$?
|
364 | ## STDOUT:
|
365 | status=1
|
366 | status=1
|
367 | status=0
|
368 | ## END
|
369 |
|
370 | #### test -b -c -S (block, character, socket)
|
371 | # NOTE: we do not have the "true" case
|
372 |
|
373 | echo -b
|
374 | test -b nonexistent
|
375 | echo status=$?
|
376 | test -b testdata
|
377 | echo status=$?
|
378 |
|
379 | echo -c
|
380 | test -c nonexistent
|
381 | echo status=$?
|
382 | test -c testdata
|
383 | echo status=$?
|
384 |
|
385 | echo -S
|
386 | test -S nonexistent
|
387 | echo status=$?
|
388 | test -S testdata
|
389 | echo status=$?
|
390 |
|
391 | ## STDOUT:
|
392 | -b
|
393 | status=1
|
394 | status=1
|
395 | -c
|
396 | status=1
|
397 | status=1
|
398 | -S
|
399 | status=1
|
400 | status=1
|
401 | ## END
|
402 |
|
403 |
|
404 | #### test -p named pipe
|
405 | mkfifo $TMP/fifo
|
406 | test -p $TMP/fifo
|
407 | echo status=$?
|
408 |
|
409 | test -p testdata
|
410 | echo status=$?
|
411 |
|
412 | ## STDOUT:
|
413 | status=0
|
414 | status=1
|
415 | ## END
|
416 |
|
417 | #### -G and -O for effective user ID and group ID
|
418 |
|
419 | mkdir -p $TMP/bin
|
420 |
|
421 | test -O $TMP/bin
|
422 | echo status=$?
|
423 | test -O __nonexistent__
|
424 | echo status=$?
|
425 |
|
426 | test -G $TMP/bin
|
427 | echo status=$?
|
428 | test -G __nonexistent__
|
429 | echo status=$?
|
430 |
|
431 | ## STDOUT:
|
432 | status=0
|
433 | status=1
|
434 | status=0
|
435 | status=1
|
436 | ## END
|
437 |
|
438 | #### -u for setuid, -g too
|
439 |
|
440 | touch $TMP/setuid $TMP/setgid
|
441 | chmod u+s $TMP/setuid
|
442 | chmod g+s $TMP/setgid
|
443 |
|
444 | test -u $TMP/setuid
|
445 | echo status=$?
|
446 |
|
447 | test -u $TMP/setgid
|
448 | echo status=$?
|
449 |
|
450 | test -g $TMP/setuid
|
451 | echo status=$?
|
452 |
|
453 | test -g $TMP/setgid
|
454 | echo status=$?
|
455 |
|
456 |
|
457 | ## STDOUT:
|
458 | status=0
|
459 | status=1
|
460 | status=1
|
461 | status=0
|
462 | ## END
|
463 |
|
464 | #### -v to test variable (bash)
|
465 | test -v nonexistent
|
466 | echo global=$?
|
467 |
|
468 | g=1
|
469 | test -v g
|
470 | echo global=$?
|
471 |
|
472 | f() {
|
473 | local f_var=0
|
474 | g
|
475 | }
|
476 |
|
477 | g() {
|
478 | test -v f_var
|
479 | echo dynamic=$?
|
480 | test -v g
|
481 | echo dynamic=$?
|
482 | test -v nonexistent
|
483 | echo dynamic=$?
|
484 | }
|
485 | f
|
486 |
|
487 | ## STDOUT:
|
488 | global=1
|
489 | global=0
|
490 | dynamic=0
|
491 | dynamic=0
|
492 | dynamic=1
|
493 | ## END
|
494 | ## N-I dash/mksh STDOUT:
|
495 | global=2
|
496 | global=2
|
497 | dynamic=2
|
498 | dynamic=2
|
499 | dynamic=2
|
500 | ## END
|
501 |
|
502 |
|
503 | #### -v tests array/assoc expression (bash) - also see spec/dbracket)
|
504 |
|
505 | case $SH in dash|mksh) exit ;; esac
|
506 |
|
507 | typeset -a array
|
508 | array=('' nonempty)
|
509 |
|
510 | [ -v array[0] ]
|
511 | echo zero=$?
|
512 |
|
513 | [ -v array[1] ]
|
514 | echo one=$?
|
515 |
|
516 | [ -v array[2] ]
|
517 | echo two=$?
|
518 |
|
519 | echo ---
|
520 |
|
521 | [ -v array[0+0] ]
|
522 | echo zero=$?
|
523 |
|
524 | [ -v array[0+1] ]
|
525 | echo one=$?
|
526 |
|
527 | [ -v array[0+2] ]
|
528 | echo two=$?
|
529 |
|
530 | echo ---
|
531 |
|
532 | typeset -A assoc
|
533 | assoc=([empty]='' [k]=v)
|
534 |
|
535 | [[ -v assoc[empty] ]]
|
536 | echo empty=$?
|
537 |
|
538 | [[ -v assoc[k] ]]
|
539 | echo k=$?
|
540 |
|
541 | [[ -v assoc[nonexistent] ]]
|
542 | echo nonexistent=$?
|
543 |
|
544 |
|
545 | ## STDOUT:
|
546 | zero=0
|
547 | one=0
|
548 | two=1
|
549 | ---
|
550 | zero=0
|
551 | one=0
|
552 | two=1
|
553 | ---
|
554 | empty=0
|
555 | k=0
|
556 | nonexistent=1
|
557 | ## END
|
558 |
|
559 | ## N-I dash/mksh STDOUT:
|
560 | ## END
|
561 |
|
562 |
|
563 | #### test -o for options
|
564 | # note: it's lame that the 'false' case is confused with the 'typo' case.
|
565 | # but checking for error code 2 is unlikely anyway.
|
566 | test -o nounset
|
567 | echo status=$?
|
568 |
|
569 | set -o nounset
|
570 | test -o nounset
|
571 | echo status=$?
|
572 |
|
573 | test -o _bad_name_
|
574 | echo status=$?
|
575 | ## STDOUT:
|
576 | status=1
|
577 | status=0
|
578 | status=1
|
579 | ## END
|
580 | ## N-I dash STDOUT:
|
581 | status=2
|
582 | status=2
|
583 | status=2
|
584 | ## END
|
585 |
|
586 | #### -nt -ot
|
587 | [ present -nt absent ] || exit 1
|
588 | [ absent -ot present ] || exit 2
|
589 | ## status: 1
|
590 |
|
591 | #### -ef
|
592 | left=$TMP/left
|
593 | right=$TMP/right
|
594 | touch $left $right
|
595 |
|
596 | ln -f $TMP/left $TMP/hardlink
|
597 |
|
598 | test $left -ef $left && echo same
|
599 | test $left -ef $TMP/hardlink && echo same
|
600 | test $left -ef $right || echo different
|
601 |
|
602 | test $TMP/__nonexistent -ef $right || echo different
|
603 |
|
604 | ## STDOUT:
|
605 | same
|
606 | same
|
607 | different
|
608 | different
|
609 | ## END
|
610 |
|
611 | #### Overflow error
|
612 | test -t 12345678910
|
613 | echo status=$?
|
614 | ## STDOUT:
|
615 | status=2
|
616 | ## END
|
617 | ## OK dash/bash STDOUT:
|
618 | status=1
|
619 | ## END
|
620 |
|
621 | #### Bug regression
|
622 | test "$ipv6" = "yes" -a "$ipv6lib" != "none"
|
623 | echo status=$?
|
624 | ## STDOUT:
|
625 | status=1
|
626 | ## END
|
627 |
|
628 |
|
629 | #### test -c
|
630 | test -c /dev/zero
|
631 | echo status=$?
|
632 | ## STDOUT:
|
633 | status=0
|
634 | ## END
|
635 |
|
636 | #### test -S
|
637 | test -S /dev/zero
|
638 | echo status=$?
|
639 | ## STDOUT:
|
640 | status=1
|
641 | ## END
|