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