1 ## oils_failures_allowed: 0
2 ## compare_shells: bash-4.4 mksh
3
4 # NOTE: zsh passes about half, and fails about half. It supports a subset of
5 # [[ I guess.
6
7 #### [[ glob matching, [[ has no glob expansion
8 [[ foo.py == *.py ]] && echo true
9 [[ foo.p == *.py ]] || echo false
10 ## STDOUT:
11 true
12 false
13 ## END
14
15 #### [[ glob matching with escapes
16 [[ 'foo.*' == *."*" ]] && echo true
17 # note that the pattern arg to fnmatch should be '*.\*'
18 ## stdout: true
19
20 #### equality
21 [[ '*.py' == '*.py' ]] && echo true
22 [[ foo.py == '*.py' ]] || echo false
23 ## STDOUT:
24 true
25 false
26 ## END
27
28 #### [[ glob matching with unquoted var
29 pat=*.py
30 [[ foo.py == $pat ]] && echo true
31 [[ foo.p == $pat ]] || echo false
32 ## STDOUT:
33 true
34 false
35 ## END
36
37 #### [[ regex matching
38 # mksh doesn't have this syntax of regex matching. I guess it comes from perl?
39 regex='.*\.py'
40 [[ foo.py =~ $regex ]] && echo true
41 [[ foo.p =~ $regex ]] || echo false
42 ## STDOUT:
43 true
44 false
45 ## END
46 ## N-I mksh stdout-json: ""
47 ## N-I mksh status: 1
48
49 #### [[ regex syntax error
50 # hm, it doesn't show any error, but it exits 2.
51 [[ foo.py =~ * ]] && echo true
52 ## status: 2
53 ## N-I mksh status: 1
54
55 #### [[ has no word splitting
56 var='one two'
57 [[ 'one two' == $var ]] && echo true
58 ## stdout: true
59
60 #### [[ has quote joining
61 var='one two'
62 [[ 'one 'tw"o" == $var ]] && echo true
63 ## stdout: true
64
65 #### [[ empty string is false
66 [[ 'a' ]] && echo true
67 [[ '' ]] || echo false
68 ## STDOUT:
69 true
70 false
71 ## END
72
73 #### && chain
74 [[ t && t && '' ]] || echo false
75 ## stdout: false
76
77 #### || chain
78 [[ '' || '' || t ]] && echo true
79 ## stdout: true
80
81 #### [[ compound expressions
82 # Notes on whitespace:
83 # - 1 and == need space seprating them, but ! and ( don't.
84 # - [[ needs whitesapce after it, but ]] doesn't need whitespace before it!
85 [[ ''||! (1 == 2)&&(2 == 2)]] && echo true
86 ## stdout: true
87
88 # NOTE on the two cases below. We're comparing
89 # (a || b) && c vs. a || (b && c)
90 #
91 # a = true, b = false, c = false is an example where they are different.
92 # && and || have precedence inside
93
94 #### precedence of && and || inside [[
95 [[ True || '' && '' ]] && echo true
96 ## stdout: true
97
98 #### precedence of && and || in a command context
99 if test True || test '' && test ''; then
100 echo YES
101 else
102 echo "NO precedence"
103 fi
104 ## stdout: NO precedence
105
106 # http://tldp.org/LDP/abs/html/testconstructs.html#DBLBRACKETS
107
108 #### Octal literals with -eq
109 shopt -u strict_arith || true
110 decimal=15
111 octal=017 # = 15 (decimal)
112 [[ $decimal -eq $octal ]] && echo true
113 [[ $decimal -eq ZZZ$octal ]] || echo false
114 ## STDOUT:
115 true
116 false
117 ## END
118 ## N-I mksh stdout: false
119 # mksh doesn't implement this syntax for literals.
120
121 #### Hex literals with -eq
122 shopt -u strict_arith || true
123 decimal=15
124 hex=0x0f # = 15 (decimal)
125 [[ $decimal -eq $hex ]] && echo true
126 [[ $decimal -eq ZZZ$hex ]] || echo false
127 ## STDOUT:
128 true
129 false
130 ## END
131 ## N-I mksh stdout: false
132
133 # TODO: Add tests for this
134 # https://www.gnu.org/software/bash/manual/bash.html#Bash-Conditional-Expressions
135 # When used with [[, the ‘<’ and ‘>’ operators sort lexicographically using the
136 # current locale. The test command uses ASCII ordering.
137
138 #### > on strings
139 # NOTE: < doesn't need space, even though == does? That's silly.
140 [[ b>a ]] && echo true
141 [[ b<a ]] || echo false
142 ## STDOUT:
143 true
144 false
145 ## END
146
147 #### != on strings
148 # NOTE: b!=a does NOT work
149 [[ b != a ]] && echo true
150 [[ a != a ]] || echo false
151 ## STDOUT:
152 true
153 false
154 ## END
155
156 #### -eq on strings
157 # This is lame behavior: it does a conversion to 0 first for any string
158 shopt -u strict_arith || true
159 [[ a -eq a ]] && echo true
160 [[ a -eq b ]] && echo true
161 ## STDOUT:
162 true
163 true
164 ## END
165
166 #### [[ compare with literal -f (compare with test-builtin.test.sh)
167 var=-f
168 [[ $var == -f ]] && echo true
169 [[ '-f' == $var ]] && echo true
170 ## STDOUT:
171 true
172 true
173 ## END
174
175 #### [[ with op variable (compare with test-builtin.test.sh)
176 # Parse error -- parsed BEFORE evaluation of vars
177 op='=='
178 [[ a $op a ]] && echo true
179 [[ a $op b ]] || echo false
180 ## status: 2
181 ## OK mksh status: 1
182
183 #### [[ with unquoted empty var (compare with test-builtin.test.sh)
184 empty=''
185 [[ $empty == '' ]] && echo true
186 ## stdout: true
187
188 #### [[ at runtime doesn't work
189 dbracket=[[
190 $dbracket foo == foo ]]
191 ## status: 127
192
193 #### [[ with env prefix doesn't work
194 FOO=bar [[ foo == foo ]]
195 ## status: 127
196
197 #### [[ over multiple lines is OK
198 # Hm it seems you can't split anywhere?
199 [[ foo == foo
200 && bar == bar
201 ]] && echo true
202 ## status: 0
203 ## STDOUT:
204 true
205 ## END
206
207 #### Argument that looks like a command word operator
208 [[ -f -f ]] || echo false
209 [[ -f == ]] || echo false
210 ## STDOUT:
211 false
212 false
213 ## END
214
215 #### Argument that looks like a real operator
216 [[ -f < ]] && echo 'should be parse error'
217 ## status: 2
218 ## OK osh status: 1
219 ## OK mksh status: 1
220
221 #### User array compared to "$@" (broken unless shopt -s strict_array)
222 # Both are coerced to string! It treats it more like an UNQUOTED ${a[@]}.
223
224 a=('1 3' 5)
225 b=(1 2 3)
226 set -- 1 '3 5'
227 [[ "$@" = "${a[@]}" ]] && echo true
228 [[ "$@" = "${b[@]}" ]] || echo false
229 ## STDOUT:
230 true
231 false
232 ## END
233
234 #### Array coerces to string (shopt -s strict_array to disallow)
235 a=('1 3' 5)
236 [[ '1 3 5' = "${a[@]}" ]] && echo true
237 [[ '1 3 4' = "${a[@]}" ]] || echo false
238 ## STDOUT:
239 true
240 false
241 ## END
242
243 #### (( array1 == array2 )) doesn't work
244 a=('1 3' 5)
245 b=('1 3' 5)
246 c=('1' '3 5')
247 d=('1' '3 6')
248
249 # shells EXPAND a and b first
250 (( a == b ))
251 echo status=$?
252
253 (( a == c ))
254 echo status=$?
255
256 (( a == d ))
257 echo status=$?
258
259 ## stdout-json: ""
260 ## status: 1
261 ## BUG bash STDOUT:
262 status=1
263 status=1
264 status=1
265 ## END
266 ## BUG bash status: 0
267
268 #### Quotes don't matter in comparison
269 [[ '3' = 3 ]] && echo true
270 [[ '3' -eq 3 ]] && echo true
271 ## STDOUT:
272 true
273 true
274 ## END
275
276 #### -eq does dynamic arithmetic parsing (not supported in OSH)
277 [[ 1+2 -eq 3 ]] && echo true
278 expr='1+2'
279 [[ $expr -eq 3 ]] && echo true # must be dynamically parsed
280 ## STDOUT:
281 true
282 true
283 ## END
284
285 #### -eq coercion produces weird results
286 shopt -u strict_arith || true
287 [[ '' -eq 0 ]] && echo true
288 ## stdout: true
289
290 #### [[ '(' ]] is treated as literal
291 [[ '(' ]]
292 echo status=$?
293 ## stdout: status=0
294
295 #### [[ '(' foo ]] is syntax error
296 [[ '(' foo ]]
297 echo status=$?
298 ## status: 2
299 ## OK mksh status: 1
300
301 #### empty ! is treated as literal
302 [[ '!' ]]
303 echo status=$?
304 ## stdout: status=0
305
306 #### [[ -z ]] is syntax error
307 [[ -z ]]
308 echo status=$?
309 ## status: 2
310 ## OK mksh status: 1
311
312 #### [[ -z '>' ]]
313 [[ -z '>' ]] || echo false # -z is operator
314 ## stdout: false
315
316 #### [[ -z '>' a ]] is syntax error
317 [[ -z '>' -- ]]
318 echo status=$?
319 ## status: 2
320 ## OK mksh status: 1
321
322 #### test whether ']]' is empty
323 [[ ']]' ]]
324 echo status=$?
325 ## status: 0
326
327 #### [[ ]] is syntax error
328 [[ ]]
329 echo status=$?
330 ## stdout-json: ""
331 ## status: 2
332 ## OK mksh status: 1
333
334 #### [[ && ]] is syntax error
335 [[ && ]]
336 echo status=$?
337 ## stdout-json: ""
338 ## status: 2
339 ## OK mksh status: 1
340
341 #### [[ a 3< b ]] doesn't work (bug regression)
342 [[ a 3< b ]]
343 echo status=$?
344 [[ a 3> b ]]
345 echo status=$?
346 ## status: 2
347
348 # Hm these shells use the same redirect trick that OSH used to!
349
350 ## BUG mksh/zsh status: 0
351 ## BUG mksh/zsh STDOUT:
352 status=0
353 status=1
354 ## END
355
356 #### tilde expansion in [[
357 HOME=/home/bob
358 [[ ~ == /home/bob ]]
359 echo status=$?
360
361 [[ ~ == */bob ]]
362 echo status=$?
363
364 [[ ~ == */z ]]
365 echo status=$?
366
367 ## STDOUT:
368 status=0
369 status=0
370 status=1
371 ## END
372
373 #### more tilde expansion
374 [[ ~ ]]
375 echo status=$?
376 HOME=''
377 [[ ~ ]]
378 echo status=$?
379 [[ -n ~ ]]
380 echo unary=$?
381
382 [[ ~ == ~ ]]
383 echo status=$?
384
385 [[ $HOME == ~ ]]
386 echo fnmatch=$?
387 [[ ~ == $HOME ]]
388 echo fnmatch=$?
389
390 ## STDOUT:
391 status=0
392 status=1
393 unary=1
394 status=0
395 fnmatch=0
396 fnmatch=0
397 ## END
398
399 #### tilde expansion with =~ (confusing)
400 case $SH in mksh) exit ;; esac
401
402 HOME=foo
403 [[ ~ =~ $HOME ]]
404 echo regex=$?
405 [[ $HOME =~ ~ ]]
406 echo regex=$?
407
408 HOME='^a$' # looks like regex
409 [[ ~ =~ $HOME ]]
410 echo regex=$?
411 [[ $HOME =~ ~ ]]
412 echo regex=$?
413
414 ## STDOUT:
415 regex=0
416 regex=0
417 regex=1
418 regex=0
419 ## END
420 ## OK zsh STDOUT:
421 regex=0
422 regex=0
423 regex=1
424 regex=1
425 ## END
426 ## N-I mksh stdout-json: ""
427
428 #### [[ ]] with redirect
429 [[ $(stdout_stderr.py) == STDOUT ]] 2>$TMP/x.txt
430 echo $?
431 echo --
432 cat $TMP/x.txt
433 ## STDOUT:
434 0
435 --
436 STDERR
437 ## END
438
439 #### special chars
440 [[ ^ == ^ ]]
441 echo caret $?
442 [[ '!' == ! ]]
443 echo bang $?
444 ## STDOUT:
445 caret 0
446 bang 0
447 ## END
448
449
450 #### \(\) in pattern (regression)
451 if [[ 'foo()' == *\(\) ]]; then echo match1; fi
452 if [[ 'foo()' == *'()' ]]; then echo match2; fi
453 if [[ 'foo()' == '*()' ]]; then echo match3; fi
454
455 shopt -s extglob
456
457 if [[ 'foo()' == *\(\) ]]; then echo match1; fi
458 if [[ 'foo()' == *'()' ]]; then echo match2; fi
459 if [[ 'foo()' == '*()' ]]; then echo match3; fi
460
461 ## STDOUT:
462 match1
463 match2
464 match1
465 match2
466 ## END
467
468 #### negative numbers - zero, decimal, octal, hex, base N
469
470 [[ -0 -eq 0 ]]; echo zero=$?
471
472 [[ -42 -eq -42 ]]; echo decimal=$?
473
474 # note: mksh doesn't do octal conversion
475 [[ -0123 -eq -83 ]]; echo octal=$?
476
477 [[ -0xff -eq -255 ]]; echo hex=$?
478
479 [[ -64#a -eq -10 ]]; echo baseN=$?
480
481 ## STDOUT:
482 zero=0
483 decimal=0
484 octal=0
485 hex=0
486 baseN=0
487 ## END
488
489 ## BUG mksh STDOUT:
490 zero=0
491 decimal=0
492 octal=1
493 hex=2
494 baseN=2
495 ## END