#!/bin/bash
if [ "$1" == 'b' ]; then
echo 1
fi
No issues detected!
Warning: use bash style ( [[ ... ]] ) testing for better performance
I'm no expert here, so maybe this question isn't very useful coming from me... Why is it important to use [[ ... ]] over [ ... ] in all cases?
[ is an alias for the test command.man test[[ is a smart, bash-internal re-implementation of test command.testman bash: "CONDITIONAL EXPRESSIONS"No, [[ is certainly not "Full backward compatible with test".
In particular, there are cases where you want expansion inside a test.
They're different tests, for different purposes.
As for faster, in bash, [ is a built-in too. Not that it should be an argument at all - if you need to shave microseconds, why use bash?
I'm actually surprised by the speed difference:
$ time for((i=0; i<1000000; i++)); do [ x ]; done
real 0m4.247s
$ time for((i=0; i<1000000; i++)); do [[ x ]]; done
real 0m3.293s
But I don't think that's a good enough reason to force people to use [[. Though I also don't think var=(-n foo); [ "${var[@]}" ] is good enough reason not to.
@arth1 At first, yea, I was bad, this is a builtin command too (I re-read the man bash). But, can you tell me an example about incompatibility?
@koalaman I use lot of static analyzer, what can force vica-versa rules about a topic. I think, if this rule is not good for everyone, then these peoples can disabled this.
@Nightfirecat, @koalaman, I don't want to enforce anyone generally. So, I absolutely prefer a by-default disabled rule, what I can turn on.
If this solution doesn't fit into the shellcheck mindset / way, I can approve absolutely!
But in this case I miss a tool for enforcing coding styles for bash. For this issue and #888, and e.g. writing if and then in same line or not. (check jscs and jslint synergy)
In other hand, the Google's recommendation is there about this question: https://google.github.io/styleguide/shell.xml#Test,_%5B_and_%5B%5B
@andras-tim Example of incompatibility include [[ not globbing LHS arguments, like:
[ -e file* ]
vs
[[ -e file* ]]
Changing the former to the latter means the script no longer works as intended.
Granted, the first one will crash if there's more than one match, but the script might be in control of that. I've seen it done for checking for semaphores, of which there should be no more than one, but whose exact name is unknown due to $$ or mktemp or similar.
Another example:
[ >logfile ] && CAN_LOG=1
This doesn't translate to
[[ >logfile ]] && CAN_LOG=1
Not that the former is good code, but it's an example of an incompatibility nevertheless.
So no, it's not fully backwards compatible, and you can't just put replace [ with [[ without looking at the test.
Even if Shellcheck is not going to suggest [[ ]], please can we at least get a warning about the non-POSIX == in that example ?
Even for valid code:
[ -n "$x" -a ! -n "$y" ]
translates to
[[ -n $x && ! -n $y ]]
And the latter does short-circuiting while the former does not, which means this _won't_ work:
[ -n "$x" -a "$(wc -l < "$x")" -lt 5 ]
Incidentally, that should probably be written to guard against $x being a huge file:
limit=5
[[ -n $x ]] && (( $( head -n$limit < "$x" | wc -l ) < limit ))
@kurahaupo A POSIX checker for shellcheck has been requested before, and I'd be happy to see it. Right now, there isn't one, and the closest you can get is shellcheck -s sh
Which is not entirely the same, but at least it helps with making scripts more portable. And it will warn about the ==.
As for -a and -o, I think those at least warrant a warning; especially -a because of the short-circuit issue. They've been deprecated for years now, and closing the test and using && and || is the recommended approach.
As for why [[ is faster than [ even though they're both builtins, that's because [[ bypasses some of the phases that apply to normal command parsing, especially globbing and wordsplitting (those take time just to inspect, even if they don't do anything).
There's already a warning for -a and -o.
What's the argument against using [ a == b ] in Bash, where this is well defined? How about [[ a == b ]]?
+koalaman I believe the most frequent argument is that == is overloaded. It's used for comparing numeric values in (()) constructs, while -eq is used for that in tests and == becomes a string comparison. (( 01 == 1 )) is true, while [ 01 == 1 ] is false, which can be confusing, and avoided by always using = to note that it's a string comparison that's different from the == in (( ... ))
I don't find that overloading to be a problem, but == is a waste of a precious character, as well as against my personal rule of "if it can be written as sh compatible, write it as sh compatible".
On Wed, 3 May 2017, koalaman wrote:
What's the argument against using
[ a == b ]in Bash
Mostly that it's neither POSIX-compliant, nor conferring any benefit; it's
an incompatibility for no purpose.
How about
[[ a == b ]]?
For both, the argument is that it's misleading: it looks like a
comparison, but it's not, it's a pattern-match.
So [[ $a == x ]] differing from [[ x == $a ]] is an unexpected asymmetry.
Sure, if the pattern happens not to have any unquoted wildcard characters
then it gives the same result as an equality test, but it just seems like
it's setting people up to fail.
@kurahaupo wrote:
it's an incompatibility for no purpose.
There is a purpose: To make it easier for C programmers. But it's a failed purpose, because " == " in bash doesn't do the same as == in C, but does the exact same as " = ", nothing more, nothing less. It's more like strcmp(foo,bar), except between (( )) where " == " behaves like "atoi(foo) == atoi(bar)"
Confused yet? That's nothing compared to > doing the job of -gt, except all the cases where it doesn't...
:-)
On Sat, 6 May 2017, arth1 wrote:
@kurahaupo wrote:
it's an incompatibility for no purpose.
There is a purpose: To make it easier for
(irony acknowledged)
Let me rephrase that:
it's an incompatibility that fulfills no purpose.
@koalaman Would it at least be possible to make this an opt-in warning if my project wants to enforce only the [[ ]]-style tests?