Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

linux shell test `-d` on empty argument

Tags:

linux

shell

Here is the code,

x=
if [ -d $x ]; then 
    echo "it's a dir"
else
    echo "not a dir"
fi

The above code gives me "it's a dir", why? $x is empty, isn't it?

like image 353
Alcott Avatar asked Aug 14 '26 18:08

Alcott


2 Answers

x=
if [ -d $x ]; then

is equivalent to:

if [ -d ] ; then

A simpler way to demonstrate what's going on is:

test -d ; echo $?

which prints 0, indicating that the test succeeded ([ is actually a command, equivalent to test except that it takes a terminating ] argument.)

But this:

test -f ; echo $?

does the same thing. Does that mean that the missing argument is both a directory and a plain file?

No, it means that it's not doing those tests.

According to the POSIX specification for the test command, its behavior depends on the number of arguments it receives.

With 0 arguments, it exits with a status of 1, indicating failure.

With 1 argument, it exits with a status of 0 (success) if the argument is not empty, or 1 (success) if the argument is empty.

With 2 arguments, the result depends on the first argument, which can be either ! (which reverses the behavior for 1 arguments), or a "unary primary" like -f or -d, or something else; if it's something else, the results are unspecified.

(POSIX also specifies the behavior for more than 2 arguments, but that's not relevant to this question.)

So this:

x=
if [ -d $x ]; then echo yes ; else echo no ; fi

prints "yes", not because the missing argument is a directory, but because the single argument -d is not the empty string.

Incidentally, the GNU Coreutils manual doesn't mention this.

So don't do that. If you want to test whether $x is a directory, enclose it in double quotes:

if [ -d "$x" ] ; then ...
like image 101
Keith Thompson Avatar answered Aug 16 '26 10:08

Keith Thompson


The stat system call, which your shell presumably uses to determine if is a directory, treats null as the current directory.

Try compiling this program and running it with no arguments:

#include <stdio.h>
#include <sys/stat.h>

int main(int argc, char* argv[]) {
  struct stat s ;

  stat(argv[1], &s) ;

  if(s.st_mode & S_IFDIR != 0) {
    printf("%s is a directory\n", argv[1]) ;
  }
}
like image 21
Paul Richter Avatar answered Aug 16 '26 10:08

Paul Richter