11 ms·
It's still relevant if you use -a, -o, or parentheses (which I guess is reason to avoid them): $ a=1; b=1; c='!'; d='!' $ [ "$a" = "$b" -a "$c" = "$d" ]
by dataflow 6y ago
It's still relevant if you use -a, -o, or parentheses (which I guess is reason to avoid them):
$ a=1; b=1; c='!'; d='!'
$ [ "$a" = "$b" -a "$c" = "$d" ]
-bash: [: too many arguments
$ [ '!' '(' "$c" = "$d" ')' ]
-bash: [: `)' expected, found !
$ echo "${BASH_VERSION}"
5.1.4(1)-release
Note that it's not even a bug here; it's necessary for disambiguation.
- arthur2e5 6y agoThe post mentions the issue is fixed by POSIX, which… notably does not standarize -o -a and parens. I guess now we know why POSIX didn't standardize those.
- hvdijk 6y agoPOSIX did standardize those, but the functionality is marked XSI, so only XSI-conforming implementations are required to provide it. There is never a reason to use them, though. They can be replaced by the shell's && and || operators, which nicely bypasses the parsing ambiguities at the same time.
- dataflow 6y ago> There is never a reason to use them, though. They can be replaced by the shell's && and || operators, which nicely bypasses the parsing ambiguities at the same time. Not sure I agree. The equivalent of more complicated expressions like (a AND b) OR (c AND d) with && and || isn't always so "nice" IMO. e.g., try it for this: [ -f a -a -f b -o -f c -a -f d ] I think the simplest syntax will require you to spawn subshells, which is neither particularly nice, nor particularly performant (especially on Windows).
- sltkr 6y agoIs this really so much worse: { test -f a && test -f b; } || { test -f c && test -f d; } ? Yes, it's more verbose, but the original expression isn't particularly readable either, and if you'd want to evaluate something like (a OR b) AND (c OR d) you'd need to introduce parentheses anyway.
- hvdijk 6y agoNote also that this does not need any subshells. I think dataflow was thinking of (test -f a && test -f b) || (test -f c && test -f d) instead, but { } isn't worse than that.
- dataflow 6y agoYeah almost. I was thinking of ([ -f a ] && [ -f b ]) || ([ -f c ] && [ -f d ]) instead of (test -f a && test -f b) || (test -f c && test -f d)
- dolmen 6y agoParentheses launch a subshell, so you probably want to use accolades instead: {[ -f a ] && [ -f b ] ;} || { [ -f c ] && [ -f d ] ;}
- dataflow 6y agoWith braces I'd prefer the test syntax actually, this is too many special characters to be comfortably readable for me. And yes I know it creates subshells, that was precisely what I was saying in my comment where I said the simplest syntax I could think of (i.e. that very code) creates subshells.
- dataflow 6y agoIt's not "so much" worse, it's just mildly worse. All I was saying here was the verbosity is a reason for using them. Obviously there are reasons not to use them too, which I said in my own top comment.
- fooblat 6y agoAlternatively you can use the newer (and highly recommended) bash syntax that is also quote safe: $ a=1; b=1; c='!'; d='!' $ [[ $a = $b && $c = $d ]] && echo true true For anyone writing bash scripts today I would avoid the old test/[ functions entirely.
- dataflow 6y agoIt's always fun to assume everyone is running Bash until your Mac's zsh or your Ubuntu's dash (or whatever) choke on your script a few times. When this happens enough times you eventually reconsider...
- linkdd 6y agoThat's what shebangs are for: #!/usr/bin/env bash If it's not there, it will fail. I expect every script with `#!/bin/sh` as shebang to be POSIX shell only.
- dataflow 6y ago> If it's not there, it will fail. Until your users/colleagues source it into another shell, or copy-paste some part of it into their shell/Makefile/Bazel/other script... and then either you feel sorry for them, or you laugh at them and blame them for burning themselves and trashing their system. (Hopefully your choice didn't cause their files to get wiped. Unless you think they deserved it for daring to paste your code somewhere else, I guess.) The world isn't perfect.
- linkdd 6y agoThis problem is not exclusive to bash, try copy-pasting python 2 code into python 3. Or ES2020 code in a browser. Or ASM z80 into an x86 program. When you're copy-pasting, you should be aware of what you're copying, and where you're pasting it. Surely, no domain in IT is idiot-proof.
- 6y ago
- deleted 6y ago[deleted]
- FirstLvR 6y agoTIL
- alerighi 6y agoWell, never seen any reason to use -a or -o. To me they are less clear and you are prone to error. I find things like: [ "$a" = "$b" ] && [ "$c" = "$d" ] much more clear.
- jolmg 6y ago> Note that it's not even a bug here; it's necessary for disambiguation. I would call it a bug when there's one valid way to read it, and [ fails to see it. I don't see the ambiguation. For example, zsh's [ doesn't have these errors: $ a=1; b=1; c='!'; d='!' $ [ "$a" = "$b" -a "$c" = "$d" ]; echo $? 0 $ [ '!' '(' "$c" = "$d" ')' ]; echo $? 1 Same result with FreeBSD's tcsh's [. I think bash's [ is just lacking the ability to backtrack while parsing its arguments. Curiously, GNU's [ fails to parse the arguments of the first, but not the second's: $ command [ "$a" = "$b" -a "$c" = "$d" ]; echo $? [: extra argument ‘!’ 2 $ command [ '!' '(' "$c" = "$d" ')' ]; echo $? 1 It seems its argument parsing works differently when using parentheses: $ command [ "$a" = "$b" -a '(' "$c" = "$d" ')' ]; echo $? 0
- dataflow 6y agoI was just being a little sloppy in what I wrote. I meant you can encounter ambiguities in the language when you start using -a/-o or (). I didn't mean those particular examples' parse trees are ambiguous.