8

How does one test for the existence of files in a directory using bash?

if ... ; then
   echo 'Found some!'
fi

To be clear, I don't want to test for the existence of a specific file. I would like to test if a specific directory contains any files.


I went with:

(
   shopt -s dotglob nullglob
   existing_files=( ./* )
   if [[ ${#existing_files[@]} -gt 0 ]] ; then
      some_command "${existing_files[@]}"
   fi
)

Using the array avoids race conditions from reading the file list twice.

ikegami
  • 367,544
  • 15
  • 269
  • 518

8 Answers8

13

From the man page:

   -f file
          True if file exists and is a regular file.

So:

if [ -f someFileName ]; then echo 'Found some!'; fi

Edit: I see you already got the answer, but for completeness, you can use the info in Checking from shell script if a directory contains files - and lose the dotglob option if you want hidden files ignored.

Community
  • 1
  • 1
Conrad Shultz
  • 8,748
  • 2
  • 31
  • 33
7

I typically just use a cheap ls -A to see if there's a response.

Pseudo-maybe-correct-syntax-example-ahoy:

if [[ $(ls -A my_directory_path_variable ) ]] then....

edit, this will work:

myDir=(./*) if [ ${#myDir[@]} -gt 1 ]; then echo "there's something down here"; fi

  • This answer should work for you, even if it's somewhat hackish. I'm going to take a stab at an all sh/bash solution. –  Jan 19 '12 at 05:39
  • It feels a bit twisted, but it does indeed work. I look forward to seeing what you come up with :) – ikegami Jan 19 '12 at 05:43
  • 1
    myDir=(./*) if [ ${#myDir[@]} -gt 1 ]; then echo "there's something down here"; fi ...here you go. plug and play. –  Jan 19 '12 at 05:43
  • @tristan: That fails if the directory contains only files whose names start with `.`. – Keith Thompson Jan 19 '12 at 05:49
  • my second version is _ever_ so slightly faster on tests for directories with 300+ files on OSX - I'm seeing about a 0.001s difference. not sure if that matters, but hey. –  Jan 19 '12 at 05:50
  • @keith thompson, i'm assuming 'that fai' to be 'that fails.' and yeah..kinda. if the script is the only file in the directory and you're setting myDir to the running directory, it will fail to recognize itself (my guess is that this behavior is due to the way that linux/unix loads the file into /proc/ or memory temporarily when executing it - but i might be wrong). to get certain files or dot files, a shopt + flags command will have to be thrown before the ${#myDir[@]} is fired off. please let me know what you find and if you want me to hunt for a solution. –  Jan 19 '12 at 05:56
  • @KeithThompson yeah, my bad. check my comment. shopt dotglob or modify the myDir=(./*) to read myDir=(./.*) –  Jan 19 '12 at 05:58
  • @tristan: You saw my comment before I edited it. If you're entering a comment on an iPad and you tap outside the text input box, it posts whatever you've typed so far. I probably should have deleted the partial comment. – Keith Thompson Jan 19 '12 at 06:15
  • @KeithThompson no worries at all - i figured that it was javascript/delay related. –  Jan 19 '12 at 06:30
  • `${#myDir[@]} -gt 1` doesn't distinguish empty from one file. `${#myDir[@]} -gt 0` works, but only under `shopt -s nullglob`. – ikegami Jan 19 '12 at 06:42
4

You can use ls in an if statement thus:

if [[ "$(ls -a1 | egrep -v '^\.$|^\.\.$')" = "" ]] ; then echo empty ; fi

or, thanks to ikegami,

if [[ "$(ls -A)" = "" ]] ; then echo empty ; fi

or, even shorter:

if [[ -z "$(ls -A)" ]] ; then echo empty ; fi

These basically list all files in the current directory (including hidden ones) that are neither . nor ...

If that list is empty, then the directory is empty.

If you want to discount hidden files, you can simplify it to:

if [[ "$(ls)" = "" ]] ; then echo empty ; fi

A bash-only solution (no invoking external programs like ls or egrep) can be done as follows:

emp=Y; for i in *; do if [[ $i != "*" ]]; then emp=N; break; fi; done; echo $emp

It's not the prettiest code in the world, it simply sets emp to Y and then, for every real file, sets it to N and breaks from the for loop for efficiency. If there were zero files, it stays as Y.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • If you `s/ls -a/ls -A/`, the need for the `egrep` disappears. – ikegami Jan 19 '12 at 05:45
  • why use egrep when you can stay within bash? also, there's no need to compare the result to an empty string. this is more expensive than it needs to be. –  Jan 19 '12 at 06:31
  • @tristan, that's probably why you got the accept rather than me :-) However, you should keep in mind that none of my solutions above, not yours, stays "within bash". They all invoke `ls`, and external executable. I'll add a bash-only solution though it'll be ugly. – paxdiablo Jan 19 '12 at 06:35
  • @paxdiablo, i reread my comment and realized that i went heavy on the "abrasive" and light on the "do you know something that i don't know?" yikes. sorry. –  Jan 19 '12 at 06:39
  • No probs, @tristan, my skin is thick enough to stop neutrinos :-) I still like your solution better since it works on the `ls` return code, rather than mucking about with strings. – paxdiablo Jan 19 '12 at 06:42
  • 1
    This notion of doing things in pure bash is silly. On my box, in a directory of moderate size (9640 files), ls -f | head | grep runs about 32 times faster than doing the glob in the shell. There's nothing wrong with using external tools. – William Pursell Jan 26 '12 at 21:01
3

Try this

if [ -f /tmp/foo.txt ]
then
    echo the file exists
fi

ref: http://tldp.org/LDP/abs/html/fto.html

you may also want to check this out: http://tldp.org/LDP/abs/html/fto.html

How about this for whether directory is empty or not

$ find "/tmp" -type f -exec echo Found file {} \;
Steve Robillard
  • 13,445
  • 3
  • 36
  • 32
  • That tests for the existence of a specific file. I would like to test for the existence of any file. – ikegami Jan 19 '12 at 05:32
1
# tested on Linux BASH

directory=$1

if test $(stat -c %h $directory) -gt 2;
then
   echo "not empty"
else
   echo "empty"
fi
Vidul
  • 10,128
  • 2
  • 18
  • 20
1
#!/bin/bash

if [ -e $1 ]; then
        echo "File exists"
else 
       echo "Files does not exist"
fi 
Xaxxon
  • 11
  • 1
  • That tests for the existence of a specific file. I would like to test for the existence of any file in a specific directory. – ikegami Jan 19 '12 at 05:37
1

I don't have a good pure sh/bash solution, but it's easy to do in Perl:

#!/usr/bin/perl

use strict;
use warnings;

die "Usage: $0 dir\n" if scalar @ARGV != 1 or not -d $ARGV[0];
opendir my $DIR, $ARGV[0] or die "$ARGV[0]: $!\n";
my @files = readdir $DIR;
closedir $DIR;
if (scalar @files == 2) { # . and ..
    exit 0;
}
else {
    exit 1;
}

Call it something like emptydir and put it somewhere in your $PATH, then:

if emptydir dir ; then
    echo "dir is empty"
else
    echo "dir is not empty"
fi

It dies with an error message if you give it no arguments, two or more arguments, or an argument that isn't a directory; it's easy enough to change if you prefer different behavior.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
0

For fun:

if ( shopt -s nullglob ; perl -e'exit !@ARGV' ./* ) ; then
   echo 'Found some!'
fi

(Doesn't check for hidden files)

ikegami
  • 367,544
  • 15
  • 269
  • 518