Is there a difference between the two code snippets below
if [[ $a == "1" ]];then
echo $a
and
if [ $a == "1" ];then
echo $a
Also, is there a difference when I use -eq in place of == in the above snippet?
As for your main question: it is a duplicate of: Is [[ ]] preferable over [ ] in bash scripts?
You can also find a (hopefully) comprehensive discussion of the differences between [ ... ] and [[ ... ]] in this answer of mine.
In short: [[ ... ]] is parsed more like you'd expect in a regular programming language, and it implements many useful extensions, but it is not POSIX-compliant.
As for "is there a difference when I use -eq in place of ==?":
= and ==, its Bash alternative, perform string comparison.
Additionally, inside [[ ... ]] only, if the RHS of = or == is unquoted, it is interpreted as a glob-style pattern to match the LHS against; contrast [[ 'a' == '*' ]] && echo match with [[ 'a' == * ]] && echo match
Note that if you use [ ... ] (rather than [[ ... ]]) for POSIX compliance (portable use with /bin/sh), you should only use =, not ==; while Bash accepts == inside [ ... ] too, other shells don't.
-eq performs integer comparison
Other string/numeric operator pairs exist (e.g., -lt for numeric less-than vs. < for alphabetical (string) less-than, based on textual sort order).
Bash Conditional Expressions lists all operators you can use inside [ ... ] and [[ ... ]] (and also with test, which is effectively an alias of [ ... ]).
Additionally, inside [[ ... ]], regular expression-matching operator =~ is available - see Bash Conditional Constructs
In bash, numeric comparison is handled differently than string comparison
For numbers,
$var1 -eq $var2 // =
$var1 -gt $var2 // >
$var1 -ge $var2 // >=
$var1 -lt $var2 // <
$var1 -le $var2 // <=
$var1 -ne $var2 // !=
For strings
$str1 = $str2 // they are equal
str1 != str2 // not equal
str // Returns True if str is not null.
-n str // Returns True if the length of str is greater than zero.
-z str // Returns True if the length of str is equal to zero.
Note that == is the same as =
Also note that the == operates differently in a double bracket comparison (this is where your [ condition ] vs [[ condition ]] question comes in) when doing pattern matching. These comparisons/operators all all explained at http://www.tldp.org/LDP/abs/html/comparison-ops.html
Related
How do I compare a variable to a string (and do something if they match)?
Using variables in if statements
if [ "$x" = "valid" ]; then
echo "x has the value 'valid'"
fi
If you want to do something when they don't match, replace = with !=. You can read more about string operations and arithmetic operations in their respective documentation.
Why do we use quotes around $x?
You want the quotes around $x, because if it is empty, your Bash script encounters a syntax error as seen below:
if [ = "valid" ]; then
Non-standard use of == operator
Note that Bash allows == to be used for equality with [, but this is not standard.
Use either the first case wherein the quotes around $x are optional:
if [[ "$x" == "valid" ]]; then
or use the second case:
if [ "$x" = "valid" ]; then
Or, if you don't need an else clause:
[ "$x" == "valid" ] && echo "x has the value 'valid'"
a="abc"
b="def"
# Equality Comparison
if [ "$a" == "$b" ]; then
echo "Strings match"
else
echo "Strings don't match"
fi
# Lexicographic (greater than, less than) comparison.
if [ "$a" \< "$b" ]; then
echo "$a is lexicographically smaller then $b"
elif [ "$a" \> "$b" ]; then
echo "$b is lexicographically smaller than $a"
else
echo "Strings are equal"
fi
Notes:
Spaces between if and [ and ] are important
> and < are redirection operators so escape it with \> and \< respectively for strings.
To compare strings with wildcards, use:
if [[ "$stringA" == *"$stringB"* ]]; then
# Do something here
else
# Do something here
fi
I have to disagree one of the comments in one point:
[ "$x" == "valid" ] && echo "valid" || echo "invalid"
No, that is not a crazy oneliner
It's just it looks like one to, hmm, the uninitiated...
It uses common patterns as a language, in a way;
And after you learned the language.
Actually, it's nice to read
It is a simple logical expression, with one special part: lazy evaluation of the logic operators.
[ "$x" == "valid" ] && echo "valid" || echo "invalid"
Each part is a logical expression; the first may be true or false, the other two are always true.
(
[ "$x" == "valid" ]
&&
echo "valid"
)
||
echo "invalid"
Now, when it is evaluated, the first is checked. If it is false, than the second operand of the logic and && after it is not relevant. The first is not true, so it can not be the first and the second be true, anyway.
Now, in this case is the the first side of the logic or || false, but it could be true if the other side - the third part - is true.
So the third part will be evaluated - mainly writing the message as a side effect. (It has the result 0 for true, which we do not use here)
The other cases are similar, but simpler - and - I promise! are - can be - easy to read!
(I don't have one, but I think being a UNIX veteran with grey beard helps a lot with this.)
The following script reads from a file named "testonthis" line by line and then compares each line with a simple string, a string with special characters and a regular expression. If it doesn't match, then the script will print the line, otherwise not.
Space in Bash is so much important. So the following will work:
[ "$LINE" != "table_name" ]
But the following won't:
["$LINE" != "table_name"]
So please use as is:
cat testonthis | while read LINE
do
if [ "$LINE" != "table_name" ] && [ "$LINE" != "--------------------------------" ] && [[ "$LINE" =~ [^[:space:]] ]] && [[ "$LINE" != SQL* ]]; then
echo $LINE
fi
done
You can also use use case/esac:
case "$string" in
"$pattern" ) echo "found";;
esac
Bash 4+ examples. Note: not using quotes will cause issues when words contain spaces, etc. Always quote in Bash, IMO.
Here are some examples in Bash 4+:
Example 1, check for 'yes' in string (case insensitive):
if [[ "${str,,}" == *"yes"* ]] ;then
Example 2, check for 'yes' in string (case insensitive):
if [[ "$(echo "$str" | tr '[:upper:]' '[:lower:]')" == *"yes"* ]] ;then
Example 3, check for 'yes' in string (case sensitive):
if [[ "${str}" == *"yes"* ]] ;then
Example 4, check for 'yes' in string (case sensitive):
if [[ "${str}" =~ "yes" ]] ;then
Example 5, exact match (case sensitive):
if [[ "${str}" == "yes" ]] ;then
Example 6, exact match (case insensitive):
if [[ "${str,,}" == "yes" ]] ;then
Example 7, exact match:
if [ "$a" = "$b" ] ;then
Enjoy.
I would probably use regexp matches if the input has only a few valid entries. E.g. only the "start" and "stop" are valid actions.
if [[ "${ACTION,,}" =~ ^(start|stop)$ ]]; then
echo "valid action"
fi
Note that I lowercase the variable $ACTION by using the double comma's. Also note that this won't work on too aged bash versions out there.
I did it in this way that is compatible with Bash and Dash (sh):
testOutput="my test"
pattern="my"
case $testOutput in (*"$pattern"*)
echo "if there is a match"
exit 1
;;
(*)
! echo there is no coincidence!
;;esac
I was struggling with the same situation for a while, here is how I could resolve:
if [ "$var1" == "$var2" ]; then
#dowhateveryouwant
fi
Be careful with the spaces left before and after the comparison sign, otherwise it won't work or it'll give you an unexpected result.
I've spent so much time on using a single equal(=) sign but didn't work. I Hope it can help.
Are you having comparison problems? (like below?)
var="true"
if [[ $var == "true" ]]; then
# It should be working, but it is not...
else
# It is falling here...
fi
Try like the =~ operator (regular expression operator) and it might work:
var="true"
if [[ $var =~ "true" ]];then
# Now it works here!!
else
# No more inequality
fi
Bash regex operator =~ (official reference)
StackOverflow further examples (here)
How do I compare a variable to a string (and do something if they match)?
Using variables in if statements
if [ "$x" = "valid" ]; then
echo "x has the value 'valid'"
fi
If you want to do something when they don't match, replace = with !=. You can read more about string operations and arithmetic operations in their respective documentation.
Why do we use quotes around $x?
You want the quotes around $x, because if it is empty, your Bash script encounters a syntax error as seen below:
if [ = "valid" ]; then
Non-standard use of == operator
Note that Bash allows == to be used for equality with [, but this is not standard.
Use either the first case wherein the quotes around $x are optional:
if [[ "$x" == "valid" ]]; then
or use the second case:
if [ "$x" = "valid" ]; then
Or, if you don't need an else clause:
[ "$x" == "valid" ] && echo "x has the value 'valid'"
a="abc"
b="def"
# Equality Comparison
if [ "$a" == "$b" ]; then
echo "Strings match"
else
echo "Strings don't match"
fi
# Lexicographic (greater than, less than) comparison.
if [ "$a" \< "$b" ]; then
echo "$a is lexicographically smaller then $b"
elif [ "$a" \> "$b" ]; then
echo "$b is lexicographically smaller than $a"
else
echo "Strings are equal"
fi
Notes:
Spaces between if and [ and ] are important
> and < are redirection operators so escape it with \> and \< respectively for strings.
To compare strings with wildcards, use:
if [[ "$stringA" == *"$stringB"* ]]; then
# Do something here
else
# Do something here
fi
I have to disagree one of the comments in one point:
[ "$x" == "valid" ] && echo "valid" || echo "invalid"
No, that is not a crazy oneliner
It's just it looks like one to, hmm, the uninitiated...
It uses common patterns as a language, in a way;
And after you learned the language.
Actually, it's nice to read
It is a simple logical expression, with one special part: lazy evaluation of the logic operators.
[ "$x" == "valid" ] && echo "valid" || echo "invalid"
Each part is a logical expression; the first may be true or false, the other two are always true.
(
[ "$x" == "valid" ]
&&
echo "valid"
)
||
echo "invalid"
Now, when it is evaluated, the first is checked. If it is false, than the second operand of the logic and && after it is not relevant. The first is not true, so it can not be the first and the second be true, anyway.
Now, in this case is the the first side of the logic or || false, but it could be true if the other side - the third part - is true.
So the third part will be evaluated - mainly writing the message as a side effect. (It has the result 0 for true, which we do not use here)
The other cases are similar, but simpler - and - I promise! are - can be - easy to read!
(I don't have one, but I think being a UNIX veteran with grey beard helps a lot with this.)
The following script reads from a file named "testonthis" line by line and then compares each line with a simple string, a string with special characters and a regular expression. If it doesn't match, then the script will print the line, otherwise not.
Space in Bash is so much important. So the following will work:
[ "$LINE" != "table_name" ]
But the following won't:
["$LINE" != "table_name"]
So please use as is:
cat testonthis | while read LINE
do
if [ "$LINE" != "table_name" ] && [ "$LINE" != "--------------------------------" ] && [[ "$LINE" =~ [^[:space:]] ]] && [[ "$LINE" != SQL* ]]; then
echo $LINE
fi
done
You can also use use case/esac:
case "$string" in
"$pattern" ) echo "found";;
esac
Bash 4+ examples. Note: not using quotes will cause issues when words contain spaces, etc. Always quote in Bash, IMO.
Here are some examples in Bash 4+:
Example 1, check for 'yes' in string (case insensitive):
if [[ "${str,,}" == *"yes"* ]] ;then
Example 2, check for 'yes' in string (case insensitive):
if [[ "$(echo "$str" | tr '[:upper:]' '[:lower:]')" == *"yes"* ]] ;then
Example 3, check for 'yes' in string (case sensitive):
if [[ "${str}" == *"yes"* ]] ;then
Example 4, check for 'yes' in string (case sensitive):
if [[ "${str}" =~ "yes" ]] ;then
Example 5, exact match (case sensitive):
if [[ "${str}" == "yes" ]] ;then
Example 6, exact match (case insensitive):
if [[ "${str,,}" == "yes" ]] ;then
Example 7, exact match:
if [ "$a" = "$b" ] ;then
Enjoy.
I would probably use regexp matches if the input has only a few valid entries. E.g. only the "start" and "stop" are valid actions.
if [[ "${ACTION,,}" =~ ^(start|stop)$ ]]; then
echo "valid action"
fi
Note that I lowercase the variable $ACTION by using the double comma's. Also note that this won't work on too aged bash versions out there.
I did it in this way that is compatible with Bash and Dash (sh):
testOutput="my test"
pattern="my"
case $testOutput in (*"$pattern"*)
echo "if there is a match"
exit 1
;;
(*)
! echo there is no coincidence!
;;esac
I was struggling with the same situation for a while, here is how I could resolve:
if [ "$var1" == "$var2" ]; then
#dowhateveryouwant
fi
Be careful with the spaces left before and after the comparison sign, otherwise it won't work or it'll give you an unexpected result.
I've spent so much time on using a single equal(=) sign but didn't work. I Hope it can help.
Are you having comparison problems? (like below?)
var="true"
if [[ $var == "true" ]]; then
# It should be working, but it is not...
else
# It is falling here...
fi
Try like the =~ operator (regular expression operator) and it might work:
var="true"
if [[ $var =~ "true" ]];then
# Now it works here!!
else
# No more inequality
fi
Bash regex operator =~ (official reference)
StackOverflow further examples (here)
I would like to recreate something like this
if ( arg1 || arg2 || arg 3) {}
And I did got so far, but I get the following error:
line 11: [.: command not found
if [ $char == $';' -o $char == $'\\' -o $char == $'\'' ]
then ...
I tried different ways, but none seemed to work. Some of the ones I tried.
For Bash, you can use the [[ ]] form rather than [ ], which allows && and || internally:
if [[ foo || bar || baz ]] ; then
...
fi
Otherwise, you can use the usual Boolean logic operators externally:
[ foo ] || [ bar ] || [ baz ]
...or use operators specific to the test command (though modern versions of the POSIX specification describe this XSI extension as deprecated -- see the APPLICATION USAGE section):
[ foo -o bar -o baz ]
...which is a differently written form of the following, which is similarly deprecated:
test foo -o bar -o baz
Bash's [[ ]] and (( )) are more powerful and flexible than [ ].
[[ ]] is for strings and (( )) is for integer logic and arithmetic
&& and || operators can be used inside [[ ]] and (( )), and () can be used for grouping
No need to quote variable expansions inside [[ ]] or (( )) - Bash doesn't do word splitting or globbing in these contexts
Inside (( )), there is no need for a $ behind variable names to expand them
[[ ]] and (( )) can span multiple lines, without the need for a line continuation with \
Using these, we can write clean, readable, and more reliable code.
Examples
Compound statements with integers
a=1 b=2 c=3
((a == 2 || (b == 2 && c == 3))) && echo yes # yields yes
Compound statements with strings
x=apple y=mango z=pear
[[ $x == orange || ($y == mango && $z == pear) ]] && echo yes # yields yes
[ equivalents for the above statements, using {}
[ "$a" -eq 2 ] || { [ "$b" -eq 2 ] && [ "$c" -eq 3 ]; }
[ "$x" == orange ] || { [ $y == mango ] && [ "$z" == pear ]; }
Related
Is double square brackets [[ ]] preferable over single square brackets [ ] in Bash?
How to use double or single brackets, parentheses, curly braces
Comparing integers: arithmetic expression or conditional expression on Unix & Linux
Test for non-zero length string in Bash: [ -n “$var” ] or [ “$var” ]
Conditional Expressions - Bash Manual
Charles' answer is correct in that it shows you how to do logical operations on commands within (and without, for that matter) an if statement, but it looks more like you want to use case here:
case $char in
\;|\\|\') echo found;;
*) echo 'not found';;
esac
In bash, to group conditionals using the [ ] construct you must surround each group using parenthesis. Each opening/closing parenthesis must be escaped and preceded/succeeded with a white space. See below:
if [ \( "$char" = "$;" \) -o \( "$char" = "$\\" \) -o \( "$char" = "$\" \) ]
As such, it's definitely best to follow everyone elses advice and use bash's newer [[ ]] construct. Lastly, as I understand it == is a relational operator intended to be used with-in arithmetic expressions. i.e. -
$((3==4))
Cameron Newham and Bill Rosenblatt, "Learning the bash Shell" Jan.1998
when I compare two strings with single equal “=” ?
and when I compare two strings with double equal “==” ?
for example:
[[ $STR = $STR1 ]]
OR
[[ $STR == $STR1 ]]
Or maybe they are both do exactly the same thing?
[[ $a == z* ]] # True if $a starts with an "z" (pattern matching).
[[ $a == "z*" ]] # True if $a is equal to z* (literal matching).
[ $a == z* ] # File globbing and word splitting take place.
[ "$a" == "z*" ] # True if $a is equal to z* (literal matching).
Everything about string comparison you can find here.
You right, both way does exactly the same thing, there is no difference at the execution.
In your conditions, take care to add quotes to your variable's name, bash could throws an error if one of them is null. Add double quotes will pass throught this error by setting variable to empty string "".
[[ "$STR1" = "$STR2" ]]
EDIT : (Thanks to comments below)
Prefer use this syntaxe [ "$STR1" == "$STR2" ] for test and shell convenience. Doubles quotes are better to use and make your condition usable with regular expression as "*.txt" but not even required.
What is the difference between =, == and -eq in shell scripting?
Is there any difference between the following?
[ $a = $b ]
[ $a == $b ]
[ $a -eq $b ]
Is it simply that = and == are only used when the variables contain numbers?
= and == are for string comparisons
-eq is for numeric comparisons
-eq is in the same family as -lt, -le, -gt, -ge, and -ne
== is specific to bash (not present in sh (Bourne shell), ...). Using POSIX = is preferred for compatibility. In bash the two are equivalent, and in sh = is the only one that will work.
$ a=foo
$ [ "$a" = foo ]; echo "$?" # POSIX sh
0
$ [ "$a" == foo ]; echo "$?" # bash-specific
0
$ [ "$a" -eq foo ]; echo "$?" # wrong
-bash: [: foo: integer expression expected
2
(Note: make sure to quote the variable expansions. Do not leave out the double-quotes above.)
If you're writing a #!/bin/bash script then I recommend using [[ instead. The double square-brackets [[...]] form has more features, a more natural syntax, and fewer gotchas that will trip you up. For example, double quotes are no longer required around $a:
$ [[ $a == foo ]]; echo "$?" # bash-specific
0
See also:
What's the difference between [ and [[ in Bash?
It depends on the Test Construct around the operator. Your options are double parentheses, double brackets, single brackets, or test.
If you use ((…)), you are testing arithmetic equality with == as in C:
$ (( 1==1 )); echo $?
0
$ (( 1==2 )); echo $?
1
(Note: 0 means true in the Unix sense and a failed test results in a non-zero number.)
Using -eq inside of double parentheses is a syntax error.
If you are using […] (or single brackets) or [[…]] (or double brackets), or test you can use one of -eq, -ne, -lt, -le, -gt, or -ge as an arithmetic comparison.
$ [ 1 -eq 1 ]; echo $?
0
$ [ 1 -eq 2 ]; echo $?
1
$ test 1 -eq 1; echo $?
0
The == inside of single or double brackets (or the test command) is one of the string comparison operators:
$ [[ "abc" == "abc" ]]; echo $?
0
$ [[ "abc" == "ABC" ]]; echo $?
1
As a string operator, = is equivalent to ==. Also, note the whitespace around = or ==: it’s required.
While you can do [[ 1 == 1 ]] or [[ $(( 1+1 )) == 2 ]] it is testing the string equality — not the arithmetic equality.
So -eq produces the result probably expected that the integer value of 1+1 is equal to 2 even though the right-hand side is a string and has a trailing space:
$ [[ $(( 1+1 )) -eq "2 " ]]; echo $?
0
While a string comparison of the same picks up the trailing space and therefore the string comparison fails:
$ [[ $(( 1+1 )) == "2 " ]]; echo $?
1
And a mistaken string comparison can produce a completely wrong answer. 10 is lexicographically less than 2, so a string comparison returns true or 0. So many are bitten by this bug:
$ [[ 10 < 2 ]]; echo $?
0
The correct test for 10 being arithmetically less than 2 is this:
$ [[ 10 -lt 2 ]]; echo $?
1
In comments, there is a question about the technical reason why using the integer -eq on strings returns true for strings that are not the same:
$ [[ "yes" -eq "no" ]]; echo $?
0
The reason is that Bash is untyped. The -eq causes the strings to be interpreted as integers if possible including base conversion:
$ [[ "0x10" -eq 16 ]]; echo $?
0
$ [[ "010" -eq 8 ]]; echo $?
0
$ [[ "100" -eq 100 ]]; echo $?
0
And 0 if Bash thinks it is just a string:
$ [[ "yes" -eq 0 ]]; echo $?
0
$ [[ "yes" -eq 1 ]]; echo $?
1
So [[ "yes" -eq "no" ]] is equivalent to [[ 0 -eq 0 ]]
Last note: Many of the Bash specific extensions to the Test Constructs are not POSIX and therefore may fail in other shells. Other shells generally do not support [[...]] and ((...)) or ==.
== is a bash-specific alias for = and it performs a string (lexical) comparison instead of a numeric comparison. eq being a numeric comparison of course.
Finally, I usually prefer to use the form if [ "$a" == "$b" ]
Several answers show dangerous examples. The OP's example, [ $a == $b ], specifically used unquoted variable substitution (as of the October 2017 edit). For [...] that is safe for string equality.
But if you're going to enumerate alternatives like [[...]], you must inform also that the right-hand-side must be quoted. If not quoted, it is a pattern match! (From the Bash man page: "Any part of the pattern may be quoted to force it to be matched as a string.").
Here in Bash, the two statements yielding "yes" are pattern matching, other three are string equality:
$ rht="A*"
$ lft="AB"
$ [ $lft = $rht ] && echo yes
$ [ $lft == $rht ] && echo yes
$ [[ $lft = $rht ]] && echo yes
yes
$ [[ $lft == $rht ]] && echo yes
yes
$ [[ $lft == "$rht" ]] && echo yes
$