How do I check if certain files exist in Bash?

2019-03-20 14:50发布

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"

4条回答
兄弟一词,经得起流年.
2楼-- · 2019-03-20 14:55

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 [ ].

查看更多
趁早两清
3楼-- · 2019-03-20 15:04

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
查看更多
萌系小妹纸
4楼-- · 2019-03-20 15:16

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.

查看更多
趁早两清
5楼-- · 2019-03-20 15:19

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; }
查看更多
登录 后发表回答