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