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 current locale. The test command uses ASCII ordering.
109
110 ### > on strings
111 # NOTE: < doesn't need space, even though == does? That's silly.
112 [[ b>a ]] && echo true
113 [[ b<a ]] || echo false
114 # stdout-json: "true\nfalse\n"
115
116 ### != on strings
117 # NOTE: b!=a does NOT work
118 [[ b != a ]] && echo true
119 [[ a != a ]] || echo false
120 # stdout-json: "true\nfalse\n"
121
122 ### -eq on strings
123 # This is lame behavior: it does a conversion to 0 first for any string
124 [[ a -eq a ]] && echo true
125 [[ a -eq b ]] && echo true
126 # stdout-json: "true\ntrue\n"
127 # OK bash/mksh stdout-json: "true\ntrue\n"
128
129 ### [[ compare with literal -f (compare with test-builtin.test.sh)
130 var=-f
131 [[ $var == -f ]] && echo true
132 [[ '-f' == $var ]] && echo true
133 # stdout-json: "true\ntrue\n"
134
135 ### [[ with op variable (compare with test-builtin.test.sh)
136 # Parse error -- parsed BEFORE evaluation of vars
137 op='=='
138 [[ a $op a ]] && echo true
139 [[ a $op b ]] || echo false
140 # status: 2
141 # OK mksh status: 1
142
143 ### [[ with unquoted empty var (compare with test-builtin.test.sh)
144 empty=''
145 [[ $empty == '' ]] && echo true
146 # stdout: true
147
148 ### [[ at runtime doesn't work
149 dbracket=[[
150 $dbracket foo == foo ]]
151 # status: 127
152
153 ### [[ with env prefix doesn't work
154 FOO=bar [[ foo == foo ]]
155 # status: 127
156
157 ### [[ over multiple lines is OK
158 # Hm it seems you can't split anywhere?
159 [[ foo == foo
160 && bar == bar
161 ]] && echo true
162 # status: 0
163 # stdout-json: "true\n"
164
165 ### Argument that looks like a command word operator
166 [[ -f -f ]] || echo false
167 [[ -f == ]] || echo false
168 # stdout-json: "false\nfalse\n"
169
170 ### Argument that looks like a real operator
171 [[ -f < ]]
172 # status: 2
173 # OK mksh status: 1
174
175 ### Does user array equal "$@" ?
176 # Oh it coerces both to a string. Lame.
177 # I think it disobeys "${a[@]}", and treats it like an UNQUOTED ${a[@]}.
178 # NOTE: set -o strict-array should make this invalid
179 a=(1 3 5)
180 b=(1 2 3)
181 set -- 1 3 5
182 [[ "$@" = "${a[@]}" ]] && echo true
183 [[ "$@" = "${b[@]}" ]] || echo false
184 ## STDOUT:
185 true
186 false
187 ## END
188
189 ### Array coerces to string
190 # NOTE: set -o strict-array should make this invalid
191 a=(1 3 5)
192 [[ '1 3 5' = "${a[@]}" ]] && echo true
193 [[ '1 3 4' = "${a[@]}" ]] || echo false
194 ## STDOUT:
195 true
196 false
197 ## END
198
199 ### Quotes don't matter in comparison
200 [[ '3' = 3 ]] && echo true
201 [[ '3' -eq 3 ]] && echo true
202 # stdout-json: "true\ntrue\n"
203
204 ### -eq with arithmetic expression!
205 [[ 1+2 -eq 3 ]] && echo true
206 expr='1+2'
207 [[ $expr -eq 3 ]] && echo true # must be dynamically parsed
208 # stdout-json: "true\ntrue\n"
209
210 ### -eq coercion produces weird results
211 [[ '' -eq 0 ]] && echo true
212 # stdout: true
213
214 ### [[ '(' ]] is treated as literal
215 [[ '(' ]]
216 echo status=$?
217 # stdout: status=0
218
219 ### [[ '(' foo ]] is syntax error
220 [[ '(' foo ]]
221 echo status=$?
222 # status: 2
223 # OK mksh status: 1
224
225 ### empty ! is treated as literal
226 [[ '!' ]]
227 echo status=$?
228 # stdout: status=0
229
230 ### [[ -z ]] is syntax error
231 [[ -z ]]
232 echo status=$?
233 # status: 2
234 # OK mksh status: 1
235
236 ### [[ -z '>' ]]
237 [[ -z '>' ]] || echo false # -z is operator
238 # stdout: false
239
240 ### [[ -z '>' a ]] is syntax error
241 [[ -z '>' -- ]]
242 echo status=$?
243 # status: 2
244 # OK mksh status: 1
245
246 ### test whether ']]' is empty
247 [[ ']]' ]]
248 echo status=$?
249 # status: 0
250
251 ### [[ ]] is syntax error
252 [[ ]]
253 echo status=$?
254 # stdout-json: ""
255 # status: 2
256 # OK mksh status: 1
257
258 ### [[ && ]] is syntax error
259 [[ && ]]
260 echo status=$?
261 # stdout-json: ""
262 # status: 2
263 # OK mksh status: 1