How do I compare a variable to a string (and do something if they match)?
-
1Also see: http://mywiki.wooledge.org/BashFAQ/031 – Dennis Williamson Feb 10 '10 at 13:44
-
Also see: [Compound if statements with multiple expressions in Bash](https://stackoverflow.com/a/55524251/6862601) – codeforester Jul 08 '19 at 19:29
12 Answers
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

- 30,738
- 21
- 105
- 131

- 303,634
- 46
- 339
- 357
-
13How does that relate to the accepted answer given in [Unexpected operator error](http://stackoverflow.com/q/2011160/95735)? I got the same error when using `[ "$1" == "on" ]`. Changing this to [ "$1" = "on" ] solved the problem. – Piotr Dobrogost Jul 29 '13 at 10:07
-
114
-
8@JohnFeminella When writing in a bash script, it should have a single `=` and not two. – user13107 Feb 06 '14 at 03:40
-
2@user13107: Not accurate. `==` is identical to `=` for string comparisons. (Also, you always want `==` for numeric comparisons.) – John Feminella Feb 06 '14 at 05:31
-
1@JohnFeminella Using `==` gives `Unexpected Operator Error` for strings as mentioned by Piotr. – user13107 Feb 06 '14 at 07:26
-
3@user13107 Then you're probably using `sh`, not `bash`. This is a question about `bash`. – John Feminella Feb 07 '14 at 13:30
-
what the difference if I use `if [ $x == "valid" ]; then` or `if [ ""$x"" == "valid" ]; then` instead of `if [ "$x" == "valid" ]; then`? – Helin Wang Feb 28 '14 at 16:24
-
@HelinWang The first one fails if `$x` contains spaces. The second one doesn't make any sense (empty string, followed by unquoted variable, followed by empty string). – John Feminella Feb 28 '14 at 17:40
-
How to compare the string if it contains the colon for ex: "test:test2" ? I am even not able to compare the same string- ex:- if [ "test:test2" == "test:test2" ]; then ... – DearDhruv Aug 26 '14 at 06:01
-
@DearDhruv You may want to check that you don't have a typo. That should work fine. e.g. `[ "foo:bar" == "foo:bar" ] && echo "equal"` prints what I expect. – John Feminella Aug 26 '14 at 06:38
-
@JohnFeminella It says:-> [: test:test2.t: unexpected operator My script is like this: `if [ "test:test2.t" == "test:test2.t" ]; then echo "Quoka App found on your device."` – DearDhruv Aug 26 '14 at 06:47
-
@JohnFeminella: Same thing happens when I use Variable and compare it to string. – DearDhruv Aug 26 '14 at 06:53
-
@JohnFeminella I am using ubuntu 14.04 LTS if I try to compare `if [ 'testt' = 'testt' ]; then` It works but I think it is for numeric comparison. It still does not work for the variable and String comparison. – DearDhruv Aug 26 '14 at 07:13
-
Are you sure you're using bash? Please double-check. Again, please try `[ "foo:bar" == "foo:bar" ] && echo "equal"` at the command line, and not in a script, to verify. If you have a specific question, you should ask a new StackOverflow question so people can help you there. – John Feminella Aug 26 '14 at 07:51
-
@JohnFeminella Yes, I am using #!/bin/bash I even tried by typing bash in terminal then run script still no success. I will start new question after some R & D. – DearDhruv Aug 26 '14 at 11:06
-
94it might be worth noting that you can't use `[ $x -eq "valid" ]`. `-eq` is the comparison operator for integers, not strings. – craq Apr 13 '15 at 09:14
-
1Note: make sure you use spaces: this will not work: `if [ "$x"=="valid" ]`! – Danijel Jan 25 '18 at 10:35
-
-
1Yes agree with @craq 's comment, the error `integer expression expected` led me here -- I was wrongly using the `-eq` operator for string comparison; now I use `=`. – Nate Anderson Jan 12 '19 at 19:26
-
2@Alex, In which cases (if ever) do I need to use the pattern `["x$yes" == "xyes"]`, that is prefixing both the variable and the string literal with an `x`? Is that a relic of old times or is it really needed in some situations? – lanoxx Mar 08 '19 at 09:36
-
@lanoxx https://stackoverflow.com/a/3093491/887836 essentially it's about the script terminating for invalid syntax if $yes expands to nothing. – Alexander Oh Mar 08 '19 at 10:14
-
@Alex, the `"x$yes"` idiom is only needed to disambiguate when using usage modes that the modern POSIX standard for test marks obsolescent (specifically, use of `-a`, `-o`, `(` and `)` to generate individual `test` expressions that combine multiple tests). There's no value to it when following good practices with post-1991 shells. – Charles Duffy Mar 24 '19 at 23:34
-
@Alex, the right way to avoid invalid syntax when `$yes` expands to nothing is to quote it as `"$yes"`. You don't need the `x` prefix for that, and the prefix doesn't fix *other* bugs in unquoted code that quoting does resolve. – Charles Duffy Mar 24 '19 at 23:35
-
This method doesn't work with bash (macOS 11.2) if both strings contain multiple lines, where the first line is equal but further lines are different - then I get always true for a "=" test. With macOS' new zsh, however, I can even leave the quotes out, as in `[ $a = $b ]`, and get the correct result for multi-line strings. – Thomas Tempelmann Feb 10 '21 at 15:29
-
-
@craq What is the rationale for "`-eq` is the comparison operator for integers, not strings"? I.e. why not making `-eq` suitable for all types? – pmor Nov 23 '22 at 08:24
-
@pmor that's just the way it was implemented. `-eq` will try to interpret everything as an integer, and do the comparison that way. That may or may not be the functionality that you're looking for. See here for more info: https://stackoverflow.com/questions/20449543/shell-equality-operators-eq – craq Nov 24 '22 at 20:16
Or, if you don't need an else clause:
[ "$x" == "valid" ] && echo "x has the value 'valid'"

- 30,738
- 21
- 105
- 131

- 30,263
- 18
- 74
- 108
-
84And if you do need an else clause and want to make a crazy one-liner: [ "$x" == "valid" ] && echo "valid" || echo "invalid" – Matt White Mar 01 '13 at 13:32
-
14
-
4@gniourf_gniourf, no problem, use `[ "$X" == "valid" ] || ( echo invalid && false ) && echo "valid" `. – 12431234123412341234123 Sep 27 '17 at 15:56
-
1Be careful with this short version. When there is no else the return value will be `1` and in a bash with `-e` flag it will cause your script to stop and a CI will not accept return value `1` too... – iRaS Oct 22 '17 at 10:08
-
5@12431234123412341234123 `{ echo invalid && false; }` is more efficient than `( echo invalid && false )`, as it avoids paying for an unnecessary subshell. – Charles Duffy Apr 13 '18 at 15:37
-
4In POSIX sh, == in place of = is undefined. [[SC2039](https://github.com/koalaman/shellcheck/wiki/SC2039)] – vhs Aug 26 '18 at 07:57
-
@iRaS it will not stop even with `-e` flag, but you have to be careful, if such a command is executed last in a function. – jarno Sep 15 '19 at 20:12
-
@12431234123412341234123 or maybe more intuitively `[[ $x == "valid" ]] && { echo "valid" || :; } || echo "invalid"` (`:` is effectively same as `true`) – jarno Sep 15 '19 at 20:29
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.

- 16,090
- 3
- 51
- 65

- 2,739
- 1
- 25
- 27
-
My issue was that `$a` actually had `" "` surrounding it as part of the string literal value, therefore I had to use the escape character to `$b` to compare the values. I was able to find this after running `bash -x ./script.sh` , the -x flag allows you to see the value of each execution and helps in debuging. – ShahNewazKhan Feb 01 '17 at 23:45
-
1Note that the alphabetical order comparison is not POSIX-standardized, so it isn't guaranteed to work on non-GNU platforms / non-bash shells. Only the operations at http://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html are guaranteed to be portable. – Charles Duffy Apr 13 '18 at 15:39
To compare strings with wildcards, use:
if [[ "$stringA" == *"$stringB"* ]]; then
# Do something here
else
# Do something here
fi

- 26,371
- 26
- 130
- 172

- 2,844
- 5
- 34
- 69
-
16It is important that the wildcards can only be used on the right side! Also note the missing `"` around the wildcards. (btw: +1 for wildcards!) – Scz May 18 '15 at 15:01
-
8The expansion `$stringB` **must** be quoted (and, incidentally, the left hand side doesn't need to be quoted): `if [[ $stringA = *"$stringB"* ]]; then`. – gniourf_gniourf Jun 15 '16 at 11:59
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.)

- 1
- 1

- 3,277
- 2
- 24
- 35
-
21The `... && ... || ...` is usually frown upon (sorry greybeard Unix veteran, you've been wrong for all this time), as it's not semantically equivalent to `if ... then ... else ...`. Don't worry, [this is a common pitfall](http://mywiki.wooledge.org/BashPitfalls#cmd1_.26.26_cmd2_.7C.7C_cmd3). – gniourf_gniourf Jun 23 '16 at 06:22
-
7@gniourf_gniourf OP is not wrong-- nor are they likely ignorant as you suggest. `... && ... || ...` is a perfectly valid pattern and a common bash idiom. Use of it does prescribe prior knowledge (which might be good to keep in mind if there are beginners in the audience), but OP has the hair to prove they know how to avoid open manhole covers. – ebpa Jan 03 '17 at 03:47
-
3@ebpa What if the statement following && returns a value of false, will execution proceed tot he statement following || ? If so that's wrong and perhaps is what gniourf is suggesting – TSG Jan 19 '17 at 15:33
-
1@TSG It is a valid pattern because `echo "valid"` is treated as an invariant; it always returns 0 ("success"). You could replace the command in that location, but if you aren't confident it will always return 0 you'll probably find trouble down the road (hence the pattern requiring prior knowledge). I'm not arguing that it is an ideal pattern; only that it is legitimate and can be used appropriately (i.e. with echo statements). FWIW `echo "valid"` *technically* could fail and return non-zero if your path is fubar or /bin/echo is missing from your system, but then you've got bigger problems. – ebpa Jan 19 '17 at 16:03
-
4I thought echo was just an example. The statement following && might still return a non-zero value – TSG Jan 19 '17 at 18:09
-
-
1I clicked on the "common pitfalls" and was not surprised. It worked exactly as expected. It's a bit contrived to use an operation that returns "false" and then performs a follow up action. His point is basically that a lot of people have a poor understanding of "truthiness", return codes, and order of operations. I'd argue, however, this is a common idiom that concisely and clearly represents intent. Some people seem to think this is "clever". However, I'd argue that's arbitrary. It's not going out of the way to obscure intent. The "clever" comes from some people having less familiarity. – Joshua Enfield Feb 23 '23 at 21:16
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

- 30,738
- 21
- 105
- 131

- 1,230
- 17
- 22
-
Use [this approach](http://stackoverflow.com/a/10929511/1983854) to go through a file. That is, remove the UUoC among other things. – fedorqui Jun 21 '16 at 10:59
-
It's not important because of `bash` but because `[` is actually an external binary (as in `which [` yields something like `/usr/bin/[`) – Patrick Bergner Jun 21 '19 at 14:07
You can also use use case/esac:
case "$string" in
"$pattern" ) echo "found";;
esac

- 30,738
- 21
- 105
- 131

- 327,991
- 56
- 259
- 343
-
1
-
@ytpillai , it is equivalency. Keep in mind you can have patterns separated by `|`, before the `)`. The `in` statement is equivalent to `then` in `if` statements. You could argue it works over a list of patterns, where each list has its own declaration of what to do, if you come from Python. Not like `substring in string`, but rather `for item in list`. Use a `*` as your last statement if you want an `else` condition. It returns on first encounter. – mazunki Nov 17 '19 at 16:33
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.

- 30,738
- 21
- 105
- 131

- 6,716
- 5
- 55
- 62
-
for me (mac GNU bash version 4.4.12(1)-release x86_64-apple-darwin17.0.0), I have to use `if [ "$a"="$b" ]` or it doesn't work...can't have spaces around the equals – spectrum Jul 21 '19 at 01:09
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.

- 870
- 9
- 14
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

- 30,738
- 21
- 105
- 131

- 879
- 9
- 11
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)

- 2,058
- 26
- 20
-
Can you link to (official) documentation for the `=~` operator? Please respond by [editing (changing) your answer](https://stackoverflow.com/posts/67427494/edit), not here in comments (***without*** "Edit:", "Update:", or similar - the answer should appear as if it was written today). – Peter Mortensen Sep 19 '21 at 18:57
-
Bash regex operator **=~** ([official reference][1])
StackOverflow further examples ([here][2]) [1]: https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Conditional-Constructs [2]: https://stackoverflow.com/questions/19441521/bash-regex-operator – Arthur Zennig Dec 19 '22 at 16:39
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.

- 35
- 6