ChatGPT解决这个技术问题 Extra ChatGPT

How to compare strings in Bash

How do I compare a variable to a string (and do something if they match)?


P
Peter Mortensen

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

How does that relate to the accepted answer given in Unexpected operator error? I got the same error when using [ "$1" == "on" ]. Changing this to [ "$1" = "on" ] solved the problem.
The spaces are needed.
@JohnFeminella When writing in a bash script, it should have a single = and not two.
@user13107 Then you're probably using sh, not bash. This is a question about bash.
it might be worth noting that you can't use [ $x -eq "valid" ]. -eq is the comparison operator for integers, not strings.
P
Peter Mortensen

Or, if you don't need an else clause:

[ "$x" == "valid" ] && echo "x has the value 'valid'"

And if you do need an else clause and want to make a crazy one-liner: [ "$x" == "valid" ] && echo "valid" || echo "invalid"
@MattWhite: this is usually a bad idea, as echo can fail.
@gniourf_gniourf, no problem, use [ "$X" == "valid" ] || ( echo invalid && false ) && echo "valid" .
@12431234123412341234123 { echo invalid && false; } is more efficient than ( echo invalid && false ), as it avoids paying for an unnecessary subshell.
In POSIX sh, == in place of = is undefined. [SC2039]
K
Karl Nicoll
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.


Thanks for the string alphabetical order comparison
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.
Note 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 pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html are guaranteed to be portable.
A
Abdull

To compare strings with wildcards, use:

if [[ "$stringA" == *"$stringB"* ]]; then
  # Do something here
else
  # Do something here
fi

It is important that the wildcards can only be used on the right side! Also note the missing " around the wildcards. (btw: +1 for wildcards!)
The expansion $stringB must be quoted (and, incidentally, the left hand side doesn't need to be quoted): if [[ $stringA = *"$stringB"* ]]; then.
i am trying to use the same wildcard logic for filename in the filepath. But it is not working for me. tried all different wildcard strings provided here. but it always goes to else case. stringA in my case is a file path /tmp/file and stringB is "file".
C
Community

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 ... && ... || ... 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.
@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 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
I thought echo was just an example. The statement following && might still return a non-zero value
@gniourf_gniourf +1 for posting the link to Bash Pitfalls! Very useful!
P
Peter Mortensen

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

Use this approach to go through a file. That is, remove the UUoC among other things.
It's not important because of bash but because [ is actually an external binary (as in which [ yields something like /usr/bin/[)
P
Peter Mortensen

You can also use use case/esac:

case "$string" in
 "$pattern" ) echo "found";;
esac

Is this equivalency or contains?
@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.
P
Peter Mortensen

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.


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
s
steviethecat

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.


P
Peter Mortensen

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

what's the difference between using a preceding ( vs not using it?
P
Peter Mortensen

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

Can you link to (official) documentation for the =~ operator? Please respond by editing (changing) your answer, not here in comments (without "Edit:", "Update:", or similar - the answer should appear as if it was written today).