50

I am trying to compare two strings in a simple shell script. I was using /bin/sh instead of /bin/bash, and after countless hours of debugging, it turns out sh (which is actually dash) can't handle this block of code:

if [ "$var" == "string" ]
then
    do something
fi

What is a portable way to compare strings using /bin/sh? I know I can always do the opposite by using !=, but I am wondering about a cleaner, portable way.

Justin M. Keyes
  • 6,679
  • 3
  • 33
  • 60
LiraNuna
  • 64,916
  • 15
  • 117
  • 140
  • 2
    You can use `[[ $var == "string" ]]` , which is POSIX, but optional (afaik). Or you use `[ "$var" = "string" ]` . Note the `""` around the variable in the single-bracket edition: it's required in case `$var` is empty – Johannes Schaub - litb Jul 07 '09 at 00:36
  • 2
    The important part is the quotes around `$var` as litb mentioned. Without the quotes, `[ $var = "value" ]` becomes `[ = "value" ]` which confuses the shell pretty horrendously. You will probably see an error like _"[: =: unary operator expected"_ when you encounter an empty variable otherwise. – D.Shawley Jul 07 '09 at 01:12
  • I understand about "$var" vs. $var, my problem was == vs. = – LiraNuna Jul 07 '09 at 01:41
  • 1
    [[ ]] is reserved by POSIX, but not at all defined. It's just reserved because it's a Korn feature I think. – TheBonsai Jul 07 '09 at 04:22

5 Answers5

72

dash is a very strict POSIX shell, if it work in dash it is almost certain it would work in other POSIX shell.

Try:

if [ "$var" = "string" ]
then
    some_command
fi
cwd
  • 53,018
  • 53
  • 161
  • 198
J-16 SDiZ
  • 26,473
  • 4
  • 65
  • 84
  • 7
    If you are thinking "what's the difference here to the syntax in the question": it's using `=` instead of `==` – davnicwil May 30 '18 at 17:25
  • How can you use wildcards in this example? I tried if [ "$OSTYPE" = "linux"* ]; then but it doesn't get linux-arm, for example... – Pitto Dec 09 '19 at 20:46
9

Why is there even a possibility that your script will be run by the "wrong" shell? I would think you could make that a pre-requisite of your product by using the standard sh-bang line at the top of your script:

#!/bin/bash

Even if a user uses a different shell, the other shells are generally still there and, if not, simply complain and state that they are a pre-req.

Exactly the same way that a specific kernel level, or the existence of awk, can be a pre-req.

For your specific question, I believe both sh and bash allow the single '=' to be used for string comparisons - that is POSIX behavior:

if [ "a" = "a" ]; then
    echo yes
fi

yes
Hans Ginzel
  • 8,192
  • 3
  • 24
  • 22
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • 3
    *"Why is there even a possibility that your script will be run by the "wrong" shell? "* - Is it possible to control which shell is used by Autoconf? (That's the reason I'm searching for the answer) – jww Nov 05 '17 at 18:35
6

Use = instead of ==. Comparisons are handled by test(1). /usr/bin/[ is typically a link to /usr/bin/test . The only difference is that if you use [ in a shell script, the ] is required as well.

Note that bash has a built-in test/[, so it doesn't actually use /usr/bin/test.

swdev
  • 2,941
  • 2
  • 25
  • 37
skoob
  • 1,411
  • 12
  • 10
1

The answers already posted are certainly correct, but it may be worthwhile to note that occasionally parameter expansion can serve the same purpose with perhaps some additional flexibility.

% p() { printf 'notvar = %b\n' "${notvar##"${string1}"}${string2}" ; }
% string1='some stuff about things\c'
% string2='some different stuff maybe'
% notvar="$string1" p
> 'some different stuff maybe'
% notvar="$string2" p
> 'some stuff about things'

Ok, so the above isn't super-useful as is, but also consider that you can use the similar methods for testing variables in here-documents, in-line variable assignments if necessary (to a degree...), or even just as a shorter (and faster!) means of writing your first statement.

[ ! "${var##"string"}" ] && _MATCH || _NOMATCH

Or even...

[ ${#var#*"${s=string}"} -lt ${#var} ] && _SUB_STRING_TEST=TRUE

Possibly even...

% p() { printf '%s is %s of %s' "$2" "${var_chk-not}" "$1"
> }<<HEREDOC
> ${in="${1##*"${2}"*}"}
> ${in:-
>     ${in="${1##"${2}"}"}
>     ${in:-${var_chk=all}
>     ${var_chk=some}
> }
> HEREDOC
%
mikeserv
  • 694
  • 7
  • 9
-3

you can use awk

awk 'BEGIN{
 string1="test"
 string2="tes1t"
 if(s1==s2){
    print "same string"
 }else{
    print "not same"
 }
}'
ghostdog74
  • 327,991
  • 56
  • 259
  • 343