user14492
user14492

Reputation: 2234

Unexpected if statement behaviour

I was running a small bash script, but I couldn't figure out why it was entering a if block even when condition should be false.

$ cat script.sh 
#!/bin/bash

if [[ "$@"="-h" || "$@"="--help" ]]
then
    echo 'Show help'
    exit
fi

echo 'Do stuff'
$ ./script.sh 
Show help
$ bash -x script.sh 
+ [[ -n =-h ]]
+ echo 'Show help'
Show help
+ exit
$ bash -x script.sh -option
+ [[ -n -option=-h ]]
+ echo 'Show help'
Show help
+ exit

So why is $@ equal to -n when I didn't pass any arguments? Also even if it is, how does -n =-h evaluate to true? When I do pass an argument -option, why is it evaluated to true, too?

Upvotes: 2

Views: 77

Answers (3)

jub0bs
jub0bs

Reputation: 66404

The other answers have already explained the problems with your code. This one shows that

  • bashisms such as [[ ... ]] are not needed,
  • you can gain flexibility by using a for loop to check whether at least one of the command-line argument matches -h or --help.

Script

#!/bin/sh

show_help=0
for arg in "$@"; do
  shift
  case "$arg" in
    "--help")
      show_help=1
      ;;
    "-h")
      show_help=1
      ;;
    *)
      ;;
  esac
done

if [ $show_help -eq 1 ]; then
  printf "Show help\n"
  exit
fi

Tests

After making the script (called "foo") executable, by running

chmod u+x foo

I get the following results

$ ./foo
$ ./foo -h
Show help
$ ./foo --help
Show help
$ ./foo bar
$ ./foo bar --help
Show help
$ ./foo bar --help baz -h
Show help

Upvotes: 1

choroba
choroba

Reputation: 242228

[[ string ]] return true if string is not empty, i.e. it's a shorcut for

[[ -n string ]]

In your case, the string was =-h, that's why you see

[[ -n =-h ]]

To test for string equiality, you have to use the = (or ==) operator, that must be preceded and followed by whitespace.

[[ "$@" = "-h" ]]

Note that "$@" means all the arguments:

set -- a b c
set -x
[[ "$@" == 'a b c' ]] && echo true

gives

+ [[ a b c == \a\ \b\ \c ]]
+ echo true
true

Upvotes: 1

John Kugelman
John Kugelman

Reputation: 362037

Whitespace is significant. Spaces between the arguments to [[ are mandatory.

if [[ "$@" = "-h" || "$@" = "--help" ]]

Also, "$@" means "all of the command-line arguments". It would be better to just check a single argument.

if [[ "$1" = "-h" || "$1" = "--help" ]]

And for what it's worth, variable expansions in [[ don't have to be quoted. It doesn't hurt, and quoting your variables actually a good habit to develop, but if you want you can remove the quotes.

if [[ $1 = -h || $1 = --help ]]

Upvotes: 4

Related Questions