1 #!/usr/bin/env bash
2
3 #### [[ glob matching, [[ has no glob expansion
4 [[ foo.py == *.py ]] && echo true
5 [[ foo.p == *.py ]] || echo false
6 ## stdout-json: "true\nfalse\n"
7
8 #### [[ glob matching with escapes
9 [[ 'foo.*' == *."*" ]] && echo true
10 # note that the pattern arg to fnmatch should be '*.\*'
11 ## stdout: true
12
13 #### equality
14 [[ '*.py' == '*.py' ]] && echo true
15 [[ foo.py == '*.py' ]] || echo false
16 ## stdout-json: "true\nfalse\n"
17
18 #### [[ glob matching with unquoted var
19 pat=*.py
20 [[ foo.py == $pat ]] && echo true
21 [[ foo.p == $pat ]] || echo false
22 ## stdout-json: "true\nfalse\n"
23
24 #### [[ regex matching
25 # mksh doesn't have this syntax of regex matching. I guess it comes from perl?
26 regex='.*\.py'
27 [[ foo.py =~ $regex ]] && echo true
28 [[ foo.p =~ $regex ]] || echo false
29 ## stdout-json: "true\nfalse\n"
30 ## N-I mksh stdout-json: ""
31 ## N-I mksh status: 1
32
33 #### [[ regex syntax error
34 # hm, it doesn't show any error, but it exits 2.
35 [[ foo.py =~ * ]] && echo true
36 ## status: 2
37 ## N-I mksh status: 1
38
39 #### [[ has no word splitting
40 var='one two'
41 [[ 'one two' == $var ]] && echo true
42 ## stdout: true
43
44 #### [[ has quote joining
45 var='one two'
46 [[ 'one 'tw"o" == $var ]] && echo true
47 ## stdout: true
48
49 #### [[ empty string is false
50 [[ 'a' ]] && echo true
51 [[ '' ]] || echo false
52 ## stdout-json: "true\nfalse\n"
53
54 #### && chain
55 [[ t && t && '' ]] || echo false
56 ## stdout: false
57
58 #### || chain
59 [[ '' || '' || t ]] && echo true
60 ## stdout: true
61
62 #### [[ compound expressions
63 # Notes on whitespace:
64 # - 1 and == need space seprating them, but ! and ( don't.
65 # - [[ needs whitesapce after it, but ]] doesn't need whitespace before it!
66 [[ ''||! (1 == 2)&&(2 == 2)]] && echo true
67 ## stdout: true
68
69 # NOTE on the two cases below. We're comparing
70 # (a || b) && c vs. a || (b && c)
71 #
72 # a = true, b = false, c = false is an example where they are different.
73 # && and || have precedence inside
74
75 #### precedence of && and || inside [[
76 [[ True || '' && '' ]] && echo true
77 ## stdout: true
78
79 #### precedence of && and || in a command context
80 if test True || test '' && test ''; then
81 echo YES
82 else
83 echo "NO precedence"
84 fi
85 ## stdout: NO precedence
86
87 # http://tldp.org/LDP/abs/html/testconstructs.html#DBLBRACKETS
88
89 #### Octal literals with -eq
90 decimal=15
91 octal=017 # = 15 (decimal)
92 [[ $decimal -eq $octal ]] && echo true
93 [[ $decimal -eq ZZZ$octal ]] || echo false
94 ## stdout-json: "true\nfalse\n"
95 ## N-I mksh stdout: false
96 # mksh doesn't implement this syntax for literals.
97
98 #### Hex literals with -eq
99 decimal=15
100 hex=0x0f # = 15 (decimal)
101 [[ $decimal -eq $hex ]] && echo true
102 [[ $decimal -eq ZZZ$hex ]] || echo false
103 ## stdout-json: "true\nfalse\n"
104 ## N-I mksh stdout: false
105
106 # TODO: Add tests for this
107 # https://www.gnu.org/software/bash/manual/bash.html#Bash-Conditional-Expressions
108 # When used with [[, the ‘<’ and ‘>’ operators sort lexicographically using the
109 # current locale. The test command uses ASCII ordering.
110
111 #### > on strings
112 # NOTE: < doesn't need space, even though == does? That's silly.
113 [[ b>a ]] && echo true
114 [[ b<a ]] || echo false
115 ## stdout-json: "true\nfalse\n"
116
117 #### != on strings
118 # NOTE: b!=a does NOT work
119 [[ b != a ]] && echo true
120 [[ a != a ]] || echo false
121 ## stdout-json: "true\nfalse\n"
122
123 #### -eq on strings
124 # This is lame behavior: it does a conversion to 0 first for any string
125 [[ a -eq a ]] && echo true
126 [[ a -eq b ]] && echo true
127 ## stdout-json: "true\ntrue\n"
128 ## OK bash/mksh stdout-json: "true\ntrue\n"
129
130 #### [[ compare with literal -f (compare with test-builtin.test.sh)
131 var=-f
132 [[ $var == -f ]] && echo true
133 [[ '-f' == $var ]] && echo true
134 ## stdout-json: "true\ntrue\n"
135
136 #### [[ with op variable (compare with test-builtin.test.sh)
137 # Parse error -- parsed BEFORE evaluation of vars
138 op='=='
139 [[ a $op a ]] && echo true
140 [[ a $op b ]] || echo false
141 ## status: 2
142 ## OK mksh status: 1
143
144 #### [[ with unquoted empty var (compare with test-builtin.test.sh)
145 empty=''
146 [[ $empty == '' ]] && echo true
147 ## stdout: true
148
149 #### [[ at runtime doesn't work
150 dbracket=[[
151 $dbracket foo == foo ]]
152 ## status: 127
153
154 #### [[ with env prefix doesn't work
155 FOO=bar [[ foo == foo ]]
156 ## status: 127
157
158 #### [[ over multiple lines is OK
159 # Hm it seems you can't split anywhere?
160 [[ foo == foo
161 && bar == bar
162 ]] && echo true
163 ## status: 0
164 ## stdout-json: "true\n"
165
166 #### Argument that looks like a command word operator
167 [[ -f -f ]] || echo false
168 [[ -f == ]] || echo false
169 ## stdout-json: "false\nfalse\n"
170
171 #### Argument that looks like a real operator
172 [[ -f < ]] && echo 'should be parse error'
173 ## status: 2
174 ## OK mksh status: 1
175
176 #### Does user array equal "$@" ?
177 # Oh it coerces both to a string. Lame.
178 # I think it disobeys "${a[@]}", and treats it like an UNQUOTED ${a[@]}.
179 # NOTE: set -o strict-array should make this invalid
180 a=(1 3 5)
181 b=(1 2 3)
182 set -- 1 3 5
183 [[ "$@" = "${a[@]}" ]] && echo true
184 [[ "$@" = "${b[@]}" ]] || echo false
185 ## STDOUT:
186 true
187 false
188 ## END
189
190 #### Array coerces to string
191 # NOTE: set -o strict-array should make this invalid
192 a=(1 3 5)
193 [[ '1 3 5' = "${a[@]}" ]] && echo true
194 [[ '1 3 4' = "${a[@]}" ]] || echo false
195 ## STDOUT:
196 true
197 false
198 ## END
199
200 #### Quotes don't matter in comparison
201 [[ '3' = 3 ]] && echo true
202 [[ '3' -eq 3 ]] && echo true
203 ## stdout-json: "true\ntrue\n"
204
205 #### -eq with arithmetic expression!
206 [[ 1+2 -eq 3 ]] && echo true
207 expr='1+2'
208 [[ $expr -eq 3 ]] && echo true # must be dynamically parsed
209 ## STDOUT:
210 true
211 true
212 ## END
213
214 #### -eq coercion produces weird results
215 [[ '' -eq 0 ]] && echo true
216 ## stdout: true
217
218 #### [[ '(' ]] is treated as literal
219 [[ '(' ]]
220 echo status=$?
221 ## stdout: status=0
222
223 #### [[ '(' foo ]] is syntax error
224 [[ '(' foo ]]
225 echo status=$?
226 ## status: 2
227 ## OK mksh status: 1
228
229 #### empty ! is treated as literal
230 [[ '!' ]]
231 echo status=$?
232 ## stdout: status=0
233
234 #### [[ -z ]] is syntax error
235 [[ -z ]]
236 echo status=$?
237 ## status: 2
238 ## OK mksh status: 1
239
240 #### [[ -z '>' ]]
241 [[ -z '>' ]] || echo false # -z is operator
242 ## stdout: false
243
244 #### [[ -z '>' a ]] is syntax error
245 [[ -z '>' -- ]]
246 echo status=$?
247 ## status: 2
248 ## OK mksh status: 1
249
250 #### test whether ']]' is empty
251 [[ ']]' ]]
252 echo status=$?
253 ## status: 0
254
255 #### [[ ]] is syntax error
256 [[ ]]
257 echo status=$?
258 ## stdout-json: ""
259 ## status: 2
260 ## OK mksh status: 1
261
262 #### [[ && ]] is syntax error
263 [[ && ]]
264 echo status=$?
265 ## stdout-json: ""
266 ## status: 2
267 ## OK mksh status: 1