324

I am doing some bash script and now I got one variable call source and one array called samples, like this:

source='country'
samples=(US Canada Mexico...)

as I want to expand the number of sources (and each source has its own samples) I tried to add some arguments to do this. I tried this:

source=""
samples=("")
if [ $1="country" ]; then
   source="country"
   samples="US Canada Mexico..."
else
   echo "try again"
fi

but when I ran my script source countries.sh country it didn't work. What am I doing wrong?

Erik Humphrey
  • 345
  • 5
  • 18
Alejandro
  • 4,945
  • 6
  • 32
  • 30
  • 2
    how does it not work? When you run it you get an error, or it says "try again", or something else? – evil otto Mar 15 '12 at 20:42
  • 2
    yes, you may think 'the question is very straightforward'. but you've been thinking about this for a while. Please consider editing your question to include required outputs and any error messages you're getting. +1 for actually trying something and good formatting of question. good luck. – shellter Mar 15 '12 at 20:46
  • Why is this code the same as the proposed and accepted solution? That's confusing... I'm guessing the initial question didn't have the spaces right after the opening bracket and before the closing bracket of the if sentence? – Stef Apr 05 '16 at 05:32
  • 7
    @Stef if you look closely, `$1="country"` vs. `$1 = "country"` – Will Oct 18 '17 at 20:46

3 Answers3

561

Don't forget about spaces:

source=""
samples=("")
if [ $1 = "country" ]; then
   source="country"
   samples="US Canada Mexico..."
else
  echo "try again"
fi
Alex L
  • 6,192
  • 1
  • 14
  • 8
  • 162
    I cannot believe that I expend three hours on this, and was only a problem of spaces!!!!... THANKS @Alex – Alejandro Mar 15 '12 at 21:03
  • 1
    Why do you use `samples="US Canada Mexico..."` after introducing the array creation before `samples=(US Canada Mexico...)`? – user unknown Mar 15 '12 at 23:15
  • 26
    I ran into issues with this when the variable on the left was an empty string. Fix was `if [ "$1" = "country" ]; then`. – andrewb Mar 20 '15 at 01:42
  • 20
    Okay thats it. Bash officially gets my vote for beeing the most outdated yet still used command language. Syntax is just so non intuitive it hurts. Really no place for it in 2016+. @Systemd authors: can you please make "building a Linux shell that doesn't suck" your next project? I'll throw money at you. – omni Apr 08 '16 at 09:18
  • 5
    @masi sometimes i think the original intent of unix was "job security through obscurity". if the tools were cryptic to use, hard to understand, and generally out of reach of the great unwashed without the inside knowledge handed down from master to padwan, it would ensure that there would always be work for those "in the know". this philosophy is evident in the whole "RFC" construct, and flowery language used in man documents, which whilst technically telling you how to use the tools, really just were there to fulfill a requirement of having documented the tools. little has changed. – unsynchronized Jun 10 '16 at 08:46
  • Didn't work for me, I had to put $1 between quotes if [ "$1" != "unik" ]; – Erwan Clügairtz May 26 '17 at 07:17
  • 4
    If scripts are at all 'logic-heavy' (>1 `if`, >0 `while`...) I strongly try to use Python. `subprocess.run` and `os.exec*` can go pretty far. – Nick T Dec 10 '18 at 16:24
  • 2
    In addition to the `"$1"` fix mentioned by others, you can also consider using the more modern (if bash only) `if [[ $1 = "country" ]]; then`, which handles empty values but also gives various other features. – Jethro Jul 07 '20 at 08:46
  • Year 2021 update: The answer doesn't work as is with bash 5.0.17. `if [[ $1 = "country" ]]; then` works. – 3VYZkz7t Apr 23 '21 at 13:23
261

You can use either "=" or "==" operators for string comparison in bash. The important factor is the spacing within the brackets. The proper method is for brackets to contain spacing within, and operators to contain spacing around. In some instances different combinations work; however, the following is intended to be a universal example.

if [ "$1" == "something" ]; then     ## GOOD

if [ "$1" = "something" ]; then      ## GOOD

if [ "$1"="something" ]; then        ## BAD (operator spacing)

if ["$1" == "something"]; then       ## BAD (bracket spacing)

Also, note double brackets are handled slightly differently compared to single brackets ...

if [[ $a == z* ]]; then   # True if $a starts with a "z" (pattern matching).
if [[ $a == "z*" ]]; then # True if $a is equal to z* (literal matching).

if [ $a == z* ]; then     # File globbing and word splitting take place.
if [ "$a" == "z*" ]; then # True if $a is equal to z* (literal matching).
starball
  • 20,030
  • 7
  • 43
  • 238
Vyke
  • 3,099
  • 1
  • 17
  • 6
16

It seems that you are looking to parse commandline arguments into your bash script. I have searched for this recently myself. I came across the following which I think will assist you in parsing the arguments:

http://rsalveti.wordpress.com/2007/04/03/bash-parsing-arguments-with-getopts/

I added the snippet below as a tl;dr

#using : after a switch variable means it requires some input (ie, t: requires something after t to validate while h requires nothing.
while getopts “ht:r:p:v” OPTION
do
     case $OPTION in
         h)
             usage
             exit 1
             ;;
         t)
             TEST=$OPTARG
             ;;
         r)
             SERVER=$OPTARG
             ;;
         p)
             PASSWD=$OPTARG
             ;;
         v)
             VERBOSE=1
             ;;
         ?)
             usage
             exit
             ;;
     esac
done

if [[ -z $TEST ]] || [[ -z $SERVER ]] || [[ -z $PASSWD ]]
then
     usage
     exit 1
fi

./script.sh -t test -r server -p password -v

ioneyed
  • 1,052
  • 7
  • 12