stefcud
stefcud

Reputation: 2315

How to test if multiple files exist using a Bash script

How can I use the test command for an arbitrary number of files, passed in using an argument with a wildcard?

For example:

test -f /var/log/apache2/access.log.* && echo "exists one or more files"

Currently, it prints

error: bash: test: too many arguments

Upvotes: 31

Views: 92361

Answers (12)

Peter Koci
Peter Koci

Reputation: 1

Faced the same issue and I put together one-liner using test, without error if no such file exists:

[ $(ls /var/log/apache2/access.log.* 2>/dev/null | wc -l) -gt 0 ] && echo "exists one or more files" || echo "no log files"

Upvotes: 0

Constantin Hong
Constantin Hong

Reputation: 867

This condition below doesn't produce stderr. the condition's blackhole (/dev/null) doesn't prevent the stderr in cmd.

if [[ $(ls -1 /var/log/apache2/access.log.* | wc -l ) -gt 0 ]] 2> /dev/null

therefore I suggests this code.

if [[ $(ls -1 /var/log/apache2/access.log.* | wc -l ) -gt 0 ]] 2> /dev/null 
then
    echo "exists one or more files."
fi

Upvotes: 1

Hui Zheng
Hui Zheng

Reputation: 10222

To avoid "too many arguments error", you need xargs. Unfortunately, test -f doesn't support multiple files. The following one-liner should work:

for i in /var/log/apache2/access.log.*; do test -f "$i" && echo "exists one or more files" && break; done

By the way, /var/log/apache2/access.log.* is called shell-globbing, not regexp. Please see Confusion with shell-globbing wildcards and Regex for more information.

Upvotes: 12

Gnadelwartz
Gnadelwartz

Reputation: 1832

more simplyfied:

if ls /var/log/apache2/access.log.* 2>/dev/null 1>&2; then
   echo "ok"
else
   echo "ko"
fi

Upvotes: 0

dmaticzka
dmaticzka

Reputation: 106

This one is suitable for use with the Unofficial Bash Strict Mode, no has non-zero exit status when no files are found.

The array logfiles=(/var/log/apache2/access.log.*) will always contain at least the unexpanded glob, so one can simply test for existence of the first element:

logfiles=(/var/log/apache2/access.log.*)

if [[ -f ${logfiles[0]} ]]
then 
  echo 'At least one file found'
else
  echo 'No file found'
fi

Upvotes: 6

Marco Montel
Marco Montel

Reputation: 581

Or using find

if [ $(find /var/log/apache2/ -type f -name "access.log.*" | wc -l) -gt 0 ]; then
  echo "ok"
else
  echo "ko"
fi

Upvotes: 1

skupjoe
skupjoe

Reputation: 111

First, store files in the directory as an array:

logfiles=(/var/log/apache2/access.log.*)

Then perform a test on the count of the array:

if [[ ${#logfiles[@]} -gt 0 ]]; then
  echo 'At least one file found'
fi

Upvotes: 11

A. Richard
A. Richard

Reputation: 236

Variation on a theme:

if ls /var/log/apache2/access.log.* >/dev/null 2>&1
then 
  echo 'At least one file found'
else
  echo 'No file found'
fi

Upvotes: 2

tdu
tdu

Reputation: 561

This solution seems to me more intuitive:

if [ `ls -1 /var/log/apache2/access.log.* 2>/dev/null | wc -l ` -gt 0 ];
then
    echo "ok"
else
    echo "ko"
fi

Upvotes: 56

duparq
duparq

Reputation: 81

You just need to test if ls has something to list:

ls /var/log/apache2/access.log.* >/dev/null 2>&1 && echo "exists one or more files"

Upvotes: 3

RobbySherwood
RobbySherwood

Reputation: 361

ls -1 /var/log/apache2/access.log.* | grep . && echo "One or more files exist."

Upvotes: 1

BenjaminBallard
BenjaminBallard

Reputation: 1482

If you wanted a list of files to process as a batch, as opposed to doing a separate action for each file, you could use find, store the results in a variable, and then check if the variable was not empty. For example, I use the following to compile all the .java files in a source directory.

SRC=`find src -name "*.java"`
if [ ! -z $SRC ]; then
    javac -classpath $CLASSPATH -d obj $SRC
    # stop if compilation fails
    if [ $? != 0 ]; then exit; fi
fi

Upvotes: 5

Related Questions