oNion
oNion

Reputation: 135

Bash script creates a file which it shouldn't be

This following script will creates a file named "Happy", i couldn't figure out why, can someone try this script and tell me what is happening? Thanks!

#!/bin/bash

str1=""
str2="Sad"
str3="Happy"

if [ "$str2">"$str3" ]
    then echo "$str2 is greater than $str3"
elif [ "$str2"<"$str3" ]
    then echo "$str2 is less than $str3"
fi

Upvotes: 2

Views: 131

Answers (2)

slevy1
slevy1

Reputation: 3832

If you rewrite the code as follows:

#!/bin/bash

    str1=""
    str2="Sad"
    str3="Happy"

    if [[ "$str2" > "$str3" ]]
        then echo "$str2 is greater than $str3"
    elif [[ "$str2" < "$str3" ]]
        then echo "$str2 is less than $str3"
    fi

then the comparisons should occur correctly and you can avoid inadvertent file creation. The extra pair of "[" and "]" takes the code out of test context, allowing for comparison and avoids file creation. More info here which states the following:

Note that the ">" needs to be escaped within a [ ] construct. ... Note that the "<" needs to be escaped within a [ ] construct.

The reason is that in a test context, i.e. using only a single pair of square brackets as in the OP code, ">" and "<" are interpreted as redirection operators. So, instead of meaning greater than and less than respectively, ">" means direct the output of a command to a file whereas "<" means give input to a command.

Upvotes: 2

chepner
chepner

Reputation: 531215

[ is just a (silly) alias for the test command; everything following it (including the mandatory closing ]) is an argument. (What you have is treated the same as if test "$str2">"$str3".)

There are two issues:

  1. The operands and the operators need to be separated by whitespace.

    # still not quite right, but ...
    if [ "$str2" > "$str3" ]
    
  2. Since > and < are interpreted as redirection operators by the shell, they have to be escaped so that they are passed as arguments to [.

    if [ "$str2 \> "$str3" ]
    

(You might think just escaping the operator would be sufficient; however, "$str2"\>"$str3" would be treated as a single string argument to test rather than three separate arguments which test will interpret as an expression. test "$str2"\>"$str3" would simply check if the single argument is empty or not.)

Since you are using bash, it's far simpler to just use [[ instead of [. [[ is not a regular command; it's special syntax recognized by bash, so that normal processing rules don't apply. Most relevant here is that > is a string comparison operator, not a redirection operator, so it doesn't need to be escaped.

    if [[ $str2 > $str3 ]]

Upvotes: 3

Related Questions