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 a=(1 3 5)
179 b=(1 2 3)
180 set -- 1 3 5
181 [[ "$@" = "${a[@]}" ]] && echo true
182 [[ "$@" = "${b[@]}" ]] || echo false
183 # stdout-json: "true\nfalse\n"
184
185 ### Array coerces to string
186 a=(1 3 5)
187 [[ '1 3 5' = "${a[@]}" ]] && echo true
188 [[ '1 3 4' = "${a[@]}" ]] || echo false
189 # stdout-json: "true\nfalse\n"
190
191 ### Quotes don't matter in comparison
192 [[ '3' = 3 ]] && echo true
193 [[ '3' -eq 3 ]] && echo true
194 # stdout-json: "true\ntrue\n"
195
196 ### -eq with arithmetic expression!
197 [[ 1+2 -eq 3 ]] && echo true
198 expr='1+2'
199 [[ $expr -eq 3 ]] && echo true # must be dynamically parsed
200 # stdout-json: "true\ntrue\n"
201
202 ### -eq coercion produces weird results
203 [[ '' -eq 0 ]] && echo true
204 # stdout: true
205
206 ### [[ '(' ]] is treated as literal
207 [[ '(' ]]
208 echo status=$?
209 # stdout: status=0
210
211 ### [[ '(' foo ]] is syntax error
212 [[ '(' foo ]]
213 echo status=$?
214 # status: 2
215 # OK mksh status: 1
216
217 ### empty ! is treated as literal
218 [[ '!' ]]
219 echo status=$?
220 # stdout: status=0
221
222 ### [[ -z ]] is syntax error
223 [[ -z ]]
224 echo status=$?
225 # status: 2
226 # OK mksh status: 1
227
228 ### [[ -z '>' ]]
229 [[ -z '>' ]] || echo false # -z is operator
230 # stdout: false
231
232 ### [[ -z '>' a ]] is syntax error
233 [[ -z '>' -- ]]
234 echo status=$?
235 # status: 2
236 # OK mksh status: 1
237
238 ### test whether ']]' is empty
239 [[ ']]' ]]
240 echo status=$?
241 # status: 0
242
243 ### [[ ]] is syntax error
244 [[ ]]
245 echo status=$?
246 # stdout-json: ""
247 # status: 2
248 # OK mksh status: 1
249
250 ### [[ && ]] is syntax error
251 [[ && ]]
252 echo status=$?
253 # stdout-json: ""
254 # status: 2
255 # OK mksh status: 1