How do I check if certain files exist in Bash?

10,489

Solution 1

How about

if [[ ! ( -f $FILE1 && -f $FILE2 ) ]]; then
    echo NOT FOUND
    exit 1
fi

# do stuff
echo OK

See help [[ and help test for the options usable with the [[ style tests. Also read this faq entry.

Your version does not work because (...) spawns a new sub-shell, in which the exit is executed. It therefor only affects that subshell, but not the executing script.

The following works instead, executing the commands between {...} in the current shell.

I should also note that you have to quote both variables to ensure there is no unwanted expansion or word splitting made (they have to be passed as one argument to [).

[ -f "$FILE1" ] && [ -f "$FILE2" ] || { echo "NOT FOUND"; exit 1; }

Solution 2

I think you're looking for:

if [ -f $FILE1 -a -f $FILE2 ]; then
    echo OK
fi

See man test for more details on what you can put inside the [ ].

Solution 3

You can list the files and check them in a loop:

file_list='file1 file2 wild*'
for file in $file_list; do
    [ -f $file ] || exit
done

do_main_stuff

Solution 4

I usually use a variant on:

arg0=$(basename $0 .sh)
error()
{
    echo "$arg0: $@" 1>&2
    exit 1
}

[ -f $FILE2 ] || error "$FILE2 not found"
[ -f $FILE1 ] || error "$FILE1 not found"

There's no particular virtue in making the shell script have a single exit point - no harm either, but fatal errors may as well terminate the script.

The only point of debate would be whether to diagnose as many problems as possible before exiting, or whether to just diagnose the first. On average, diagnosing just the first is a whole lot easier.

Share:
10,489
Frank
Author by

Frank

Updated on July 07, 2022

Comments

  • Frank
    Frank almost 2 years

    In a bash script, I have to check for the existence of several files.

    I know an awkward way to do it, which is as follows, but that would mean that my main program has to be within that ugly nested structure:

    if [ -f $FILE1 ]
    then
    if [ -f $FILE2 ]
    then
      echo OK
      # MAIN PROGRAM HERE
    fi
    fi
    

    The following version does not work:

    ([ -f $FILE1 ] && [ -f $FILE2 ]) ||  ( echo "NOT FOUND"; exit 1 )
    echo OK
    

    It prints

    NOT FOUND
    OK
    

    Is there an elegant way to do this right?

    UPDATE: See the accepted answer. In addition, in terms of elegance I like Jonathan Leffler's answer:

    arg0=$(basename $0 .sh)
    error()
    {
        echo "$arg0: $@" 1>&2
        exit 1
    }
    
    [ -f $FILE2 ] || error "$FILE2 not found"
    [ -f $FILE1 ] || error "$FILE1 not found"