This question already has answers here: How to compare strings in Bash (11 answers) Closed 3 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 need spaces:
if [ "$s1" == "$s2" ]
"$s1" == "$s2"
statement or it will not work. Also, this works too: if test "$s1" = "$s2"
==
doesn't work on ash, dash, or other places baseline POSIX implementations of test
. Use =
instead.
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.
; then
and fi
parts.
==
doesn't work on ash, dash, or other places baseline POSIX implementations of test
. Use =
instead.
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
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.
==
" is incorrect. Bash supports both =
and ==
. Also, if you have #!/bin/bash
at the start of your script, you can make it executable and run it like ./filename.bash
(not that the file extension is important).
#!/bin/sh
or #!/bin/bash
as the first line of the script, you simply run it with ./filename
and the actual file name can be completely arbitrary.
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.
s1='*'
and s2='*'
, and you'll see that leaving out the double quotes is a serious mistake.
$ if [ "$s1" == "$s2" ]; then echo match; fi
match
$ test "s1" = "s2" ;echo match
match
$
[[
extension would be superior for versatility, robustness, and convenience.
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
.
command
or $(command). Im sure you can TEST it then make it better.
s2
contains globs: to fix this, you need to quote the expansion $s2
: "${s1/*"$s2"*/0}"
. But there are other subtle bugs that are impossible to fix: e.g., if s1
is a list of 0
's: s1=000000; s2=some_other_stuff
will claim a match. So I would highly recommend against using this method! Another bug: s1=--; s2=stuff
. Starting from bash 4.4, s1=--help; s2=stuff
would also spam standard output.
Success story sharing
if [ "$s1" = "$s2" ]
. See also Rahul's answer[
is a command (actually, an alternate name for the command calledtest
); if you runwhich [
, you'll see there's actually an executable file for it on disk (even though the shell may provide a built-in implementation as a performance optimization). Just like you have to put a space between the name of the commandls
before the name of the file you want it to print, you need to put a space after the name of the[
command and its first argument, and between each argument it's passed (if invoked as[
rather thantest
, it expects its last argument to be]
).