This question already has answers here:
How to compare strings in Bash
(12 answers)
Closed 4 years ago.
I'm trying to get an if statement to work in Bash (using Ubuntu):
#!/bin/bash
s1="hi"
s2="hi"
if ["$s1" == "$s2"]
then
echo match
fi
I've tried various forms of the if statement, using [["$s1" == "$s2"]], with and without quotes, using =, == and -eq, but I still get the following error:
[hi: command not found
I've looked at various sites and tutorials and copied those, but it doesn't work - what am I doing wrong?
Eventually, I want to say if $s1 contains $s2, so how can I do that?
I did just work out the spaces bit... :/ How do I say contains?
I tried
if [[ "$s1" == "*$s2*" ]]
but it didn't work.
For string equality comparison, use:
if [[ "$s1" == "$s2" ]]
For string does NOT equal comparison, use:
if [[ "$s1" != "$s2" ]]
For the a contains b, use:
if [[ $s1 == *"$s2"* ]]
(and make sure to add spaces between the symbols):
Bad:
if [["$s1" == "$s2"]]
Good:
if [[ "$s1" == "$s2" ]]
You should be careful to leave a space between the sign of '[' and double quotes where the variable contains this:
if [ "$s1" == "$s2" ]; then
# ^ ^ ^ ^
echo match
fi
The ^s show the blank spaces you need to leave.
You need spaces:
if [ "$s1" == "$s2" ]
I suggest this one:
if [ "$a" = "$b" ]
Notice the white space between the openning/closing brackets and the variables and also the white spaces wrapping the '=' sign.
Also, be careful of your script header. It's not the same thing whether you use
#!/bin/bash
or
#!/bin/sh
Here's the source.
Bash 4+ examples. Note: not using quotes will cause issues when words contain spaces, etc. Always quote in Bash IMO.
Here are some examples 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
This question has already great answers, but here it appears that there is a slight confusion between using single equal (=) and double equals (==) in
if [ "$s1" == "$s2" ]
The main difference lies in which scripting language you are using. If you are using Bash then include #!/bin/bash in the starting of the script and save your script as filename.bash. To execute, use bash filename.bash - then you have to use ==.
If you are using sh then use #!/bin/sh and save your script as filename.sh. To execute use sh filename.sh - then you have to use single =. Avoid intermixing them.
I would suggest:
#!/bin/bash
s1="hi"
s2="hi"
if [ $s1 = $s2 ]
then
echo match
fi
Without the double quotes and with only one equals.
$ if [ "$s1" == "$s2" ]; then echo match; fi
match
$ test "s1" = "s2" ;echo match
match
$
I don't have access to a Linux box right now, but [ is actually a program (and a Bash builtin), so I think you have to put a space between [ and the first parameter.
Also note that the string equality operator seems to be a single =.
This is more a clarification than an answer! Yes, the clue is in the error message:
[hi: command not found
which shows you that your "hi" has been concatenated to the "[".
Unlike in more traditional programming languages, in Bash, "[" is a command just like the more obvious "ls", etc. - it's not treated specially just because it's a symbol, hence the "[" and the (substituted) "$s1" which are immediately next to each other in your question, are joined (as is correct for Bash), and it then tries to find a command in that position: [hi - which is unknown to Bash.
In C and some other languages, the "[" would be seen as a different "character class" and would be disjoint from the following "hi".
Hence you require a space after the opening "[".
Use:
#!/bin/bash
s1="hi"
s2="hi"
if [ "x$s1" == "x$s2" ]
then
echo match
fi
Adding an additional string inside makes it more safe.
You could also use another notation for single-line commands:
[ "x$s1" == "x$s2" ] && echo match
For a version with pure Bash and without test, but really ugly, try:
if ( exit "${s1/*$s2*/0}" )2>/dev/null
then
echo match
fi
Explanation: In ( )an extra subshell is opened. It exits with 0 if there was a match, and it tries to exit with $s1 if there was no match which raises an error (ugly). This error is directed to /dev/null.
What does the following bash syntax mean:
function use_library {
local name=$1
local enabled=1
[[ ,${LIBS_FROM_GIT}, =~ ,${name}, ]] && enabled=0
return $enabled
}
I don't particularly understand the line [[ ,${LIBS_FROM_GIT}, =~ ,${name}, ]]. Is it some kind of regex or string comparison?
This is a trick to compare variables and prevent a weird behaviour if some of them are not defined / are empty.
You can use , or any other. The main thing is that it wants to compare ${LIBS_FROM_GIT} with ${name} and prevent the case when one of them is empty.
As indicated by Etan Reisner in comments, [[ doesn't have empty variable expansion problems. So this trick is usually used when comparing with a single [:
This doesn't work:
$ [ $d == $f ] && echo "yes"
bash: [: a: unary operator expected
But it does if we add a string around both variables:
$ [ ,$d, == ,$f, ] && echo "yes"
$
Finally, note you can use directly this:
[[ ,${LIBS_FROM_GIT}, =~ ,${name}, ]] && return 0 || return 1
This question already has answers here:
unary operator expected in shell script when comparing null value with string
(2 answers)
"unary operator expected" error in Bash if condition
(6 answers)
Closed 8 years ago.
Please follow the following example (please notice that STRING is null)
Get Error
[root#linux /tmp]# STRING=
[root#linux /tmp]# [ $STRING = dog ] && echo "yes its a dog"
bash: [: =: unary operator expected
Syntax without Error
[root#linux /tmp]# STRING=
[root#linux /tmp]# [[ $STRING = dog ]] && echo "yes its a dog"
[root#linux /tmp]# [[ $STRING != dog ]] && echo "yes its a dog"
yes its a dog
Why when I am using Single Square brackets I get - unary operator expected ?
But in case of Double Square brackets the syntax give good results
Unlike [[ ]], single square brackets are subject to word splitting like normal commands. Think of it similarly as passing arguments to test builtin. [[ ]] are special and variables within it are not split with IFS. This is why it's preferable to use [[ ]] since it's more efficient and safer.
This one is just one of the things you can't do with [. With [ you'd play around with { } and ( ) to make it work. Note that ( ) summons a subshell and { } would always need a semicolon in the end which is ugly. However you can do it safely with [[ ]]:
[[ a != b && c != d && ( something || something ) ]]
By the way to fix your problem you have to place the variable in double-quotes to prevent splitting:
[ "$STRING" = dog ]
With [[ it's not needed.
Sere Word Splitting: https://www.gnu.org/software/bash/manual/html_node/Word-Splitting.html
Add:
It seems like $STRING there was actually skipped as an argument for being empty instead of being split. Similarly the concept of it being interpreted as a normal command would apply and applying double quotes would fix it.
Because [[ is special. [ needs to retain Bourne shell compatibility, including its limitations. Since [[ is a construct introduced separately in bash, it can be fixed.
It's tough to search on, but this is very frequently asked. Try googling for "bash square brackets" and you will see lots of discussions on this topic, mostly on SO:
https://www.google.com/search?q=bash+square+brackets
https://serverfault.com/questions/52034/what-is-the-difference-between-double-and-single-square-brackets-in-bash
http://mywiki.wooledge.org/BashGuide/TestsAndConditionals#Conditional_Blocks_.28if.2C_test_and_.5B.5B.29
The short answer is to always use [[ unless you know otherwise...
I have the following strings in bash
str1="any string"
str2="any"
I want to check if str2 is a substring of str1
I can do it in this way:
c=`echo $str1 | grep $str2`
if [ $c != "" ]; then
...
fi
Is there a more efficient way of doing this?
You can use wild-card expansion *.
str1="any string"
str2="any"
if [[ "$str1" == *"$str2"* ]]
then
echo "str2 found in str1"
fi
Note that * expansion will not work with single [ ].
str1="any string"
str2="any"
Old school (Bourne shell style):
case "$str1" in *$str2*)
echo found it
esac
New school (as speakr shows), however be warned that the string to the right will be viewed as a regular expression:
if [[ $str1 =~ $str2 ]] ; then
echo found it
fi
But this will work too, even if you're not exactly expecting it:
str2='.*[trs].*'
if [[ $str1 =~ $str2 ]] ; then
echo found it
fi
Using grep is slow, since it spawns a separate process.
You can use bash regexp matching without using grep:
if [[ $str1 =~ $str2 ]]; then
...
fi
Note that you don't need any surrounding slashes or quotes for the regexp pattern. If you want to use glob pattern matching just use == instead of =~ as operator.
Some examples can be found here.
if echo $str1 | grep -q $str2 #any command
then
.....
fi
Looking at other Bash scripts, I see people comparing variables like: $S == $T while at other times I see the variable being wrapped inside strings: "$S" == "$T".
Some experiments seem to suggest that both do the same. The demo below will print equal in both cases (tested with GNU bash, version 4.2.37):
#!/usr/bin/env bash
S="text"
T="text"
if [[ $S == $T ]]; then
echo "equal"
fi
if [[ "$S" == "$T" ]]; then
echo "equal"
fi
My question: if there's a difference between $S == $T and "$S" == "$T", what is it?
If you use [[ they are almost the same, but not quite...
When the == and != operators are used, the string to the right of the operator is
considered a pattern and matched according to the rules described below under Pattern
Matching. [...]
Any part of the pattern may be quoted to force it to be matched as a string.
If you use [ then you have to use quotes unless you know that the variables cannot be empty or contain whitespace.
Just to be on the safe side, you probably want to quote all your variables all the time.