In a code review

I am being pointed out that I should change such a test structure:

[ ! -f "$1" ] &&
print_error_and_exit "The given argument is not an existing file."

to something similar, specifically:

[ ! -e "$1" ] ...

But I can't find any information about this test -e other than that is in info test; quoting relevant chapters:

16.3.3 File characteristic tests

‘-e FILE’
     True if FILE exists.

16.3.1 File type tests

‘-f FILE’
     True if FILE exists and is a regular file.


As I would like to understand 100% what I am doing, may I ask for deeper clarification on differences and usage of these two types of test commands?


That sounds like my review!

Testing with -e will return true for non-regular files: directories, pipes, sockets, devices, etc.

Note that symlinks are a special case - test normally uses the type of the pointed-to file, rather than the link itself (except for test -L, aka test -h).

In the referenced review, you might want to be able to read from a FIFO. (On the other hand, it certainly won't work to read from a directory).

Later in the review, you really don't want to overwrite a device (though you may want to write to FIFO, so fine-tune according to your needs).

  • Many systems allow reading from directories (though you would not do it directly, you would use things like opendir()/readdir()) – Stéphane Chazelas Jun 20 '18 at 11:49
  • @StéphaneChazelas; whilst that's true, the read format of the directory is incompatible with what's expected by the program concerned; that's what I meant when I say "it won't work". – Toby Speight Nov 12 '18 at 10:32

Some "files" are actually directories (-d), FIFOs (-p), device nodes (-b and -c), etc. They exist, but aren't regular files.


As you are using the test to avoid creating a directory entry with a name that already exists, it does not matter what the entry is (regular file, directory, fifo, device node or other) only that it already exists and can not be created (as the name is already in use).

The -f test only detect "regular files". The -e detect some other types.

This is closer to your intent:

[ -e "$output_filename" ] && 
    print_error_and_exit 6 "Destination file name exists."

However the -e does not detect links. You need to use this construct:

[ -e "$output_filename" ] || [ -L "$output_filename" ] && 
    print_error_and_exit 6 "Destination file name exists."

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.