Bash – Why Does [ -d $dirname ] Match When Variable is Empty or Unset?

bashshell-script

Well I've this code

dirname=

if [ -d $dirname ];
 then
 cd $dirname && rm *
fi

as you see I've this empty variable, what I want to know is why when using thing like this empty variable with the single square brackets it removes all the user's home directory files

And if I used the double square brackets it does not remove the user's home directory files

Like this

dirname=

if [[ -d $dirname ]];
 then
 cd $dirname && rm *
fi

I've read the difference syntax when using both Single Square Brackets and Double Square Brackets

May I know why this happens ?

Best Answer

When cd is not passed an argument, it will change to the default directory (in most cases, the user's home directory, $HOME).

The interesting part of this question is that when you pass nothing to the -d operator of the bash test or [ built-in, bash appears to exit with 0 (in my opinion, this is unexpected).

When you set dirname to an empty variable, you're essentially running this:

if [ -d ]; then
    cd && rm *
fi

To me, it's surprising that the code inside this if block is executed, but I can confirm on my machine that it is. As a comment above explains, test is not interpreting the -d as an operator anymore and is simply returning 0 because it's a non-null string. One way to help guard against this kind of behavior is to make sure you quote your variables:

if [ -d "$dirname" ]; then
    cd "$dirname" && rm *
fi

In this case, if $dirname is empty, you'll be passing "" to the -d operator which correctly evaluates a non-zero exit code so the code inside the block is not executed.

Related Question