Bash – Brackets in if condition: why am I getting syntax errors without whitespace

bashshellshell-scripttestwhitespace

I am using the below script to move two days back when script runs at starting two days of the year and also check first and second days of every month and move two days back.

if [$month="01"] && [$day="01"];
then
    date="$last_month/$yes_day/$last_year"
      fulldate="$last_month/$yes_day/$last_year"
else
if [$month="01"] && [$day="02"];
then
         date="$last_month/$yes_day/$last_year"
      fulldate="$last_month/$yes_day/$last_year"
else
   if [ $day = "01" ];
then
    date="$last_month/$yes_day/$year"
            fulldate="$year$last_month$yes_day"
else
        if [ $day = "02" ];
then
    date="$last_month/$yes_day/$year"
        fulldate="$year$last_month$yes_day"
else
    date="$month/$yes_day/$year"
        fulldate="$year$month$yes_day"
                fi
               fi
              fi
fi

But my bad am getting the below error message

Etime_script.sh: line 19: [06=01]: command not found
Etime_script.sh: line 24: [06=01]: command not found

Best Answer

[ is neither a metacharacter nor a control operator (not even a reserved word; same for ]) thus it needs whitespace around it. Otherwise the shell "sees" the command [01=01] instead of the command [ with the separate parameters 01, =, 01, and ]. Each operator and operand needs to be a separate argument to the [ command, so whitespace is necessary around the operators as well.

if [ "$month" = "01" ]

[$month="01"] is a wildcard pattern matching any of the characters in $month or "01. If it doesn't match anything, it's left alone.

If there is a semicolon after the closing bracket, you don't need a space before it, because the semicolon is always part of a separate token.

if [ "$month" = "01" ]; then

The same goes for bash's (and ksh's and zsh's) double bracket syntax.

More than one condition

There are two ways to combine conditions:

  1. within [

  2. with separate [ commands combined with && or ||

Grouping with brackets is probably easier within [.

if [ "$month" = "01" -a "$day" = "01" ] # -a for and, -o for or

if [ "$month" = "01" ] && [ "$day" = "01" ]

The first one should be avoided as it's unreliable (try for instance with month='!'). Problems with strange variable content can be avoided by using the safe string (if there is one) first; or by using [[/]] instead of [/]:

if [ "01" = "$month" -a "01" = "$day" ]
Related Question