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
252 #### -eq coercion produces weird results
253 shopt -u strict_arith || true
254 [[ '' -eq 0 ]] && echo true
255 ## stdout: true
256
257 #### [[ '(' ]] is treated as literal
258 [[ '(' ]]
259 echo status=$?
260 ## stdout: status=0
261
262 #### [[ '(' foo ]] is syntax error
263 [[ '(' foo ]]
264 echo status=$?
265 ## status: 2
266 ## OK mksh status: 1
267
268 #### empty ! is treated as literal
269 [[ '!' ]]
270 echo status=$?
271 ## stdout: status=0
272
273 #### [[ -z ]] is syntax error
274 [[ -z ]]
275 echo status=$?
276 ## status: 2
277 ## OK mksh status: 1
278
279 #### [[ -z '>' ]]
280 [[ -z '>' ]] || echo false # -z is operator
281 ## stdout: false
282
283 #### [[ -z '>' a ]] is syntax error
284 [[ -z '>' -- ]]
285 echo status=$?
286 ## status: 2
287 ## OK mksh status: 1
288
289 #### test whether ']]' is empty
290 [[ ']]' ]]
291 echo status=$?
292 ## status: 0
293
294 #### [[ ]] is syntax error
295 [[ ]]
296 echo status=$?
297 ## stdout-json: ""
298 ## status: 2
299 ## OK mksh status: 1
300
301 #### [[ && ]] is syntax error
302 [[ && ]]
303 echo status=$?
304 ## stdout-json: ""
305 ## status: 2
306 ## OK mksh status: 1
307
308 #### [[ a 3< b ]] doesn't work (bug regression)
309 [[ a 3< b ]]
310 echo status=$?
311 [[ a 3> b ]]
312 echo status=$?
313 ## status: 2
314
315 # Hm these shells use the same redirect trick that OSH used to!
316
317 ## BUG mksh/zsh status: 0
318 ## BUG mksh/zsh STDOUT:
319 status=0
320 status=1
321 ## END
322
323 #### tilde expansion in [[
324 HOME=/home/bob
325 [[ ~ == /home/bob ]]
326 echo status=$?
327
328 [[ ~ == */bob ]]
329 echo status=$?
330
331 [[ ~ == */z ]]
332 echo status=$?
333
334 ## STDOUT:
335 status=0
336 status=0
337 status=1
338 ## END
339
340 #### more tilde expansion
341 [[ ~ ]]
342 echo status=$?
343 HOME=''
344 [[ ~ ]]
345 echo status=$?
346 [[ -n ~ ]]
347 echo unary=$?
348
349 [[ ~ == ~ ]]
350 echo status=$?
351
352 [[ $HOME == ~ ]]
353 echo fnmatch=$?
354 [[ ~ == $HOME ]]
355 echo fnmatch=$?
356
357 ## STDOUT:
358 status=0
359 status=1
360 unary=1
361 status=0
362 fnmatch=0
363 fnmatch=0
364 ## END
365
366 #### tilde expansion with =~ (confusing)
367 case $SH in (mksh) exit ;; esac
368
369 HOME=foo
370 [[ ~ =~ $HOME ]]
371 echo regex=$?
372 [[ $HOME =~ ~ ]]
373 echo regex=$?
374
375 HOME='^a$' # looks like regex
376 [[ ~ =~ $HOME ]]
377 echo regex=$?
378 [[ $HOME =~ ~ ]]
379 echo regex=$?
380
381 ## STDOUT:
382 regex=0
383 regex=0
384 regex=1
385 regex=0
386 ## END
387 ## OK zsh STDOUT:
388 regex=0
389 regex=0
390 regex=1
391 regex=1
392 ## END
393 ## N-I mksh stdout-json: ""
394
395 #### [[ ]] with redirect
396 [[ $(stdout_stderr.py) == STDOUT ]] 2>$TMP/x.txt
397 echo $?
398 echo --
399 cat $TMP/x.txt
400 ## STDOUT:
401 0
402 --
403 STDERR
404 ## END
405
406 #### special chars
407 [[ ^ == ^ ]]
408 echo caret $?
409 [[ '!' == ! ]]
410 echo bang $?
411 ## STDOUT:
412 caret 0
413 bang 0
414 ## END
415
416
417 #### \(\) in pattern (regression)
418 if [[ 'foo()' == *\(\) ]]; then echo match1; fi
419 if [[ 'foo()' == *'()' ]]; then echo match2; fi
420 if [[ 'foo()' == '*()' ]]; then echo match3; fi
421
422 shopt -s extglob
423
424 if [[ 'foo()' == *\(\) ]]; then echo match1; fi
425 if [[ 'foo()' == *'()' ]]; then echo match2; fi
426 if [[ 'foo()' == '*()' ]]; then echo match3; fi
427
428 ## STDOUT:
429 match1
430 match2
431 match1
432 match2
433 ## END
434