12

i have a question

i try some function like

DIR=/path/tmp/

if [ -d "$DIR" ]; then

and

if [ -f "$DIR" ]; then

but only check /path/tmp this path

how can i do?

fifty arashi
  • 545
  • 2
  • 8
  • 14

7 Answers7

20

From the Bash FAQ #4 -- How can I check whether a directory is empty or not?

shopt -s nullglob dotglob
files=(*)
(( ${#files[*]} )) || echo directory is empty
shopt -u nullglob dotglob

This small script fills the array files with each file found in the path expansion *. It then checks to see the size of the array and if it's 0 it prints 'directory is empty'. This will work with hidden files thanks to the use of dotglob.

Note

Answers which ask to parse ls is in general a bad idea and poor form. To understand why, read Why you shouldn't parse the output of ls

Community
  • 1
  • 1
SiegeX
  • 135,741
  • 24
  • 144
  • 154
17

You can use ls -A for this:

if [ "$(ls -A "$DIR" 2> /dev/null)" == "" ]; then
    # The directory is empty
fi

-A shows all hidden files and directories except the . and .. that are always there, so it will be blank in an empty directory and non-blank in a directory with any files or subdirectories.

The 2> /dev/null throws away any error messages ls may print (note that checking a non-existant directory will yield a false positive, but you said you already checked that it existed). Checking a directory where you do not have read access also yields a false positive.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 1
    This could be unfavorable if the directory contains huge amount of (long name) entries. Also, "$DIR" needs quotes. To account for that - `... [ "$(ls -A "$DIR" 2>/dev/null | head -n 1)" == "" ] ...` – Zrin Mar 07 '17 at 12:14
  • @Zrin: It feels very strange to put quotes in quotes without any escaping or anything, but I tested it and you're absolutely right (at least, my test with a directory name with a space failed with my original and worked with your change). Thanks! Does the `| head -n 1` actually help anything, though? `ls` will still produce the full list won't it? – T.J. Crowder Mar 07 '17 at 12:32
  • @t-j-crowder `| head -n 1` will take the first line from `ls`, output it and then cut the input - i.e. it says "that's enough!" There is also a nice solution with `read` instead of `head` - try `| read` and check exit code. – Zrin Mar 08 '17 at 01:10
  • @Zrin: I know what `head` does. But what does it achieve here? `ls` is still going to do all the work of reading the large number of names, regardless. – T.J. Crowder Mar 08 '17 at 05:52
  • You're right that `ls -A` will read the whole directory into memory and sort it before outputing the first line. The advantage of piping through `head` is that bash wouldn't need to read all of it in (thinking e.g. of large maildirs). The disadvantage is that it's starting another process. Perhaps `ls -AU` starts the output right away? Perhaps `if ! ls -AU | read _; then echo 'it's empty'; fi` – Zrin Mar 11 '17 at 16:15
2
[ -z "$(find "$DIR" -maxdepth 0 -empty)" ] || echo "$DIR is empty!"

find has predicate -empty which tests if a directory or file is empty, so it will list the directory only if it's empty. -z tests if output of find is empty. If it is, then the directory contains entries, if it isn't then it's empty.

In other code words:

[ -n "$(find "$DIR" -maxdepth 0 -empty)" ] && echo "$DIR is empty!"

Another quite nice one:

if ! ls -AU "$DIR" | read _; then
    echo "$DIR is empty!"
fi
Zrin
  • 919
  • 15
  • 25
1

why don't use ls -v ? so will print out empty if no file such as

if $(ls -v $DIR)
wizztjh
  • 6,979
  • 6
  • 58
  • 92
0

This tells me if the directory is empty or if it's not, the number of files it contains.

directory="/path/tmp"
number_of_files=$(ls -A $directory | wc -l)

if [ "$number_of_files" == "0" ]; then
    echo "directory $directory is empty"
else
    echo "directory $directory contains $number_of_files files"
fi
Daishi
  • 12,681
  • 1
  • 19
  • 22
0

To do this using only shell built-ins (it should work for all shells I have worked with):

if test "`echo /tmp/testdir/* /tmp/testdir/.?*`" = \
    "/tmp/testdir/* /tmp/testdir/.."; then
  [...]
fi

We do not check /tmp/testdir/.* because that will expand to /tmp/testdir/. /tmp/testdir/.. for an empty folder.

Another built-in-only variant:

for i in /tmp/testdir/* /tmp/testdir/.?*; do
    test -e $i || break
    [...]
    break
done
michaeljt
  • 1,106
  • 8
  • 17
-1

rmdir "$DIR"

If $? is 1, the directory isn't empty. If 0, it was empty and it gets removed.

You may recreate it if you don't intend to remove it: mkdir "$DIR"

Jahid
  • 21,542
  • 10
  • 90
  • 108
Simone
  • 11,655
  • 1
  • 30
  • 43
  • 3
    He didn't say he wanted to remove the directory. Removing it just to find out if it's empty is a very bad idea. – T.J. Crowder Nov 23 '10 at 07:41
  • 7
    Because you're removing the directory, and he didn't say he wanted to do that. Maybe there's another process that's about to write to the directory. Maybe he doesn't have rights to remove it. The point is, it's a destructive operation and one isn't required. – T.J. Crowder Nov 23 '10 at 07:47
  • 1
    To be fair, I think this answer is still useful. Maybe someone's looking at this question with a use-case where a destructive try-removing-and-then-re-create thing is a non-issue, and there is a *simplicity* to this approach which other approaches just don't have. – mtraceur Jun 17 '21 at 06:41