149

From a shell script, how do I check if a directory contains files?

Something similar to this

if [ -e /some/dir/* ]; then echo "huzzah"; fi;

but which works if the directory contains one or several files (the above one only works with exactly 0 or 1 files).

danorton
  • 11,804
  • 7
  • 44
  • 52
ionn
  • 1,493
  • 2
  • 10
  • 5

30 Answers30

178

Three best tricks


shopt -s nullglob dotglob; f=your/dir/*; ((${#f}))

This trick is 100% bash and invokes (spawns) a sub-shell. The idea is from Bruno De Fraine and improved by teambob's comment.

files=$(shopt -s nullglob dotglob; echo your/dir/*)
if (( ${#files} ))
then
  echo "contains files"
else 
  echo "empty (or does not exist or is a file)"
fi

Note: no difference between an empty directory and a non-existing one (and even when the provided path is a file).

There is a similar alternative and more details (and more examples) on the 'official' FAQ for #bash IRC channel:

if (shopt -s nullglob dotglob; f=(*); ((${#f[@]})))
then
  echo "contains files"
else 
  echo "empty (or does not exist, or is a file)"
fi

[ -n "$(ls -A your/dir)" ]

This trick is inspired from nixCraft's article posted in 2007. Add 2>/dev/null to suppress the output error "No such file or directory".
See also Andrew Taylor's answer (2008) and gr8can8dian's answer (2011).

if [ -n "$(ls -A your/dir 2>/dev/null)" ]
then
  echo "contains files (or is a file)"
else
  echo "empty (or does not exist)"
fi

or the one-line bashism version:

[[ $(ls -A your/dir) ]] && echo "contains files" || echo "empty"

Note: ls returns $?=2 when the directory does not exist. But no difference between a file and an empty directory.


[ -n "$(find your/dir -prune -empty)" ]

This last trick is inspired from gravstar's answer where -maxdepth 0 is replaced by -prune and improved by phils's comment.

if [ -n "$(find your/dir -prune -empty 2>/dev/null)" ]
then
  echo "empty (directory or file)"
else
  echo "contains files (or does not exist)"
fi

a variation using -type d:

if [ -n "$(find your/dir -prune -empty -type d 2>/dev/null)" ]
then
  echo "empty directory"
else
  echo "contains files (or does not exist or is not a directory)"
fi

Explanation:

  • find -prune is similar than find -maxdepth 0 using less characters
  • find -empty prints the empty directories and files
  • find -type d prints directories only

Note: You could also replace [ -n "$(find your/dir -prune -empty)" ] by just the shorten version below:

if [ `find your/dir -prune -empty 2>/dev/null` ]
then
  echo "empty (directory or file)"
else
  echo "contains files (or does not exist)"
fi

This last code works most of the cases but be aware that malicious paths could express a command...

oHo
  • 51,447
  • 27
  • 165
  • 200
  • 3
    I think you can simplify the find option to `[ -n "$(find "your/dir" -prune -empty)" ]`, to avoid the repetition of the directory path. – phils Nov 27 '13 at 02:27
  • Whilst using `if [ ``ls -A your/dir`` ]` in a script I came to the conclusion that it works fine for a directory with 0, 1 or 2 subdirectories, but fails for a directory with more than 2 subdirectories. `line 17: [: 20150424-002813: unary operator expected` where `20150424-002813` was one of the directory names. The used shell was `/bin/bash/`. I finally changed it to `ls "$destination" | tail -1` – Christophe De Troyer Apr 23 '15 at 22:31
  • Hi @ChristopheDeTroyer I cannot reproduce your issue. On my side `if [ ``ls -A my/dir`` ]` exits on error `bash: [: -A: binary operator expected`. Tested on bash versions 4.1.2 and 4.2.53. – oHo Apr 28 '15 at 15:04
  • You are missing the `-n` test options in your last code snippet. – maxschlepzig Oct 29 '16 at 15:48
  • Thanks @maxschlepzig for your feedback. I have updated the third section. But in fact both commands produce same result. I have added the alternative version as a note saying that malicious paths could express a command. Is it OK for you? Cheers – oHo Oct 31 '16 at 15:43
  • 2
    Well, I was mainly motivated to comment because of the perceived inconsistency (since the `-n` variant was in the headline but then not in the paragraph below). So, yes, it's fine. – maxschlepzig Nov 01 '16 at 07:50
  • If `[[ $(ls -A your/dir) ]] && echo "contains files" || echo "empty"` returns an error, how to hide the error message? – Sigur Apr 21 '17 at 01:41
  • @Sigur `ls -A your/dir` can print `"ls: cannot access your/dir: No such file or directory"` on the [stderr](https://en.wikipedia.org/wiki/Standard_streams#Standard_error_.28stderr.29). To hide this error use `ls -A your/dir 2>\dev\null`. Thereby, the full command line becomes: `[[ $(ls -A your/dir 2>\dev\null) ]] && echo "contains files" || echo "empty"`. Do not hide stdout because it is used to detect if directory is empty (i.e. do not use `1>/dev/null` or `&>/dev/null` or `1>-` or any other similar stuff) – oHo Apr 21 '17 at 11:05
  • Thanks. Also I'd like to print the `empty` and `exit` the script, but only if it fails. Otherwise, continue. – Sigur Apr 21 '17 at 13:23
  • @olibre, not exactly. If the dir contains `txt` just continue the script without any message. If not, prints warning and stop the script. I am not able to execute `exit` if and only if the test fails. – Sigur Apr 21 '17 at 13:30
  • In this case, it prints `empty` if `ls` fails and stops. But if `ls` is true, it also stops. The `exit` is being executed in any case. – Sigur Apr 21 '17 at 15:24
  • You are right @Sigur. :-? I forgot the curly brackets `{ }` (braces). :-/ This does what you want: `[[ $(ls -A your/dir 2>\dev\null) ]] || { echo "empty" && exit ; }` Cheers ;-) – oHo Apr 22 '17 at 06:44
  • @olibre, I should had imagined about the braces. It makes sense. Thanks. – Sigur Apr 22 '17 at 12:42
  • 2
    I'm using your -n solution, still my script stills complains about this `ls: cannot access '/path': No such file or directory`. Is there a way I can suppress this message? I would like to fail silently there. – Freedo Jan 10 '18 at 18:08
  • Thank you @Freedo for your feedback. The answer has been updated using `2>/dev/null` to suppress the output error `"No such file or directory"`. Have fune and Happy new year ;-) – oHo Jan 11 '18 at 13:21
  • Thanks. I really like: Add 2>/dev/null to suppress the output error "No such file or directory"! – dave Jan 06 '22 at 04:00
89

The solutions so far use ls. Here's an all bash solution:

#!/bin/bash
shopt -s nullglob dotglob     # To include hidden files
files=(/some/dir/*)
if [ ${#files[@]} -gt 0 ]; then echo "huzzah"; fi
Bruno De Fraine
  • 45,466
  • 8
  • 54
  • 65
  • 9
    as long as you remember to set the options back to their original value at the end of the script :) – Jean Sep 18 '08 at 11:07
  • This is a slightly improved version that takes care of resetting the bash settings: `shopt -q nullglob || resetnullglob=1; shopt -s nullglob; shopt -q dotglob || resetdotglob=1; shopt -s dotglob; files=(/some/dir/*); [ "$files" ] && echo "wowzers"; [ "$resetdotglob" ] && shopt -u dotglob; [ "$resetnullglob" ] && shopt -u nullglob;` – user123444555621 Jun 07 '11 at 15:15
  • 13
    Why not use a subshell to reset the settings: `files=$(shopt -s nullglob;shopt -s dotglob;echo /some/dir/*)` – teambob Oct 11 '12 at 03:29
  • @teambob if using a subshell: `files=$(shopt -s nullglob;shopt -s dotglob;echo /some/dir/*)` – stoutyhk Jul 04 '13 at 17:40
  • 7
    @teambob if using a sub-shell: `files=$(shopt -s nullglob;shopt -s dotglob;echo /some/dir/*)` then the if statement should change to `if [ ${#files} -gt 0 ];` or maybe you just forgot the () around the sub-shell command? `files=($(shopt -s nullglob;shopt -s dotglob;echo /some/dir/*))` – stoutyhk Jul 04 '13 at 17:48
  • 2
    @stoutyhk $(...) restores the settings, no separate subshell is required. Using $(...) spawns a new instance of the shell. The environment of this new instance is thrown away once the command is finished. Edit: Found a reference tldp.org/LDP/abs/html/commandsub.html "Command substitution invokes a subshell." – teambob Jul 15 '13 at 23:42
  • 1
    You can keep it all inside the if test, no need for arrays: `if [ -z $(shopt -s nullglob dotglob; echo /some/dir/*) ]; then my_stuff; fi`, maybe use the short-circuit hack of the boolean operators. Wrap it in a function for readability. – pupitetris Mar 26 '17 at 17:51
55

How about the following:

if find /some/dir/ -maxdepth 0 -empty | read v; then echo "Empty dir"; fi

This way there is no need for generating a complete listing of the contents of the directory. The read is both to discard the output and make the expression evaluate to true only when something is read (i.e. /some/dir/ is found empty by find).

Roman Cheplyaka
  • 37,738
  • 7
  • 72
  • 121
mweerden
  • 13,619
  • 5
  • 32
  • 32
  • 3
    or simply `find /some/dir/ -maxdepth 0 -empty -exec echo "huzzah" \;` – doubleDown Nov 12 '12 at 02:34
  • 5
    +1 This the most elegant solution. It does not involve parsing of `ls` output and it does not rely on non-default shell features. –  May 16 '13 at 17:56
  • 8
    It does, however, rely on the non-standard `-maxdepth` and `-empty` primaries. – chepner Oct 18 '13 at 17:43
  • This one also distinguishes if its an actual directory. It doesn't tell if it's a file if it's empty! Bravo! – Artfaith Jun 04 '21 at 14:58
27

Try:

if [ ! -z `ls /some/dir/*` ]; then echo "huzzah"; fi
Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
  • This worked for me, but I can't format this d*mn message!!!
    export tmp=`/bin/ls /* 2> /dev/null` if [ ! -z "$tmp" ]; then echo Something is there fi
    – AndrewStone May 25 '11 at 20:00
  • 2
    For Bash idiots like me, if you want to check the opposite - that the directory is empty - just use if [ -z `ls /some/dir/*` ]; then echo "huzzah"; fi – Chris Moschini Sep 24 '13 at 16:38
  • 6
    You can use `-n` instead of `! -z` (they're both equivalent, but why not use the shorter form when it exists). – n.st Jan 26 '14 at 02:18
  • WIth ZSH this example throws an error, the idea is to not have the error thrown... `BigGray% if [ ! -z `ls /some/dir/*` ]; then echo "huzzah"; fi zsh: no matches found: /some/dir/* ` – Hvisage Feb 20 '17 at 11:11
  • doesn't work for me without double quotes around `ls...` in bash – letmutx Feb 25 '19 at 12:14
18

Take care with directories with a lot of files! It could take a some time to evaluate the ls command.

IMO the best solution is the one that uses

find /some/dir/ -maxdepth 0 -empty
Zombo
  • 1
  • 62
  • 391
  • 407
Gravstar
  • 1,071
  • 6
  • 10
16
# Works on hidden files, directories and regular files
### isEmpty()
# This function takes one parameter:
# $1 is the directory to check
# Echoes "huzzah" if the directory has files
function isEmpty(){
  if [ "$(ls -A $1)" ]; then
    echo "huzzah"
  else 
    echo "has no files"
  fi
}
glenn jackman
  • 238,783
  • 38
  • 220
  • 352
gr8can8dian
  • 161
  • 1
  • 2
8
DIR="/some/dir"
if [ "$(ls -A $DIR)" ]; then
     echo 'There is something alive in here'
fi
Jens
  • 69,818
  • 15
  • 125
  • 179
Andrew Taylor
  • 1,850
  • 18
  • 19
7

Could you compare the output of this?

 ls -A /some/dir | wc -l
DGM
  • 26,629
  • 7
  • 58
  • 79
5

This may be a really late response but here is a solution that works. This line only recognizes th existance of files! It will not give you a false positive if directories exist.

if find /path/to/check/* -maxdepth 0 -type f | read
  then echo "Files Exist"
fi
Zombo
  • 1
  • 62
  • 391
  • 407
5

ZSH

I know the question was marked for bash; but, just for reference, for zsh users:

Test for non-empty directory

To check if foo is non-empty:

$ for i in foo(NF) ; do ... ; done

where, if foo is non-empty, the code in the for block will be executed.

Test for empty directory

To check if foo is empty:

$ for i in foo(N/^F) ; do ... ; done

where, if foo is empty, the code in the for block will be executed.

Notes

We did not need to quote the directory foo above, but we can do so if we need to:

$ for i in 'some directory!'(NF) ; do ... ; done

We can also test more than one object, even if it is not a directory:

$ mkdir X     # empty directory
$ touch f     # regular file
$ for i in X(N/^F) f(N/^F) ; do echo $i ; done  # echo empty directories
X

Anything that is not a directory will just be ignored.

Extras

Since we are globbing, we can use any glob (or brace expansion):

$ mkdir X X1 X2 Y Y1 Y2 Z
$ touch Xf                    # create regular file
$ touch X1/f                  # directory X1 is not empty
$ touch Y1/.f                 # directory Y1 is not empty
$ ls -F                       # list all objects
X/ X1/ X2/ Xf Y/ Y1/ Y2/ Z/
$ for i in {X,Y}*(N/^F); do printf "$i "; done; echo  # print empty directories
X X2 Y Y2

We can also examine objects that are placed in an array. With the directories as above, for example:

$ ls -F                       # list all objects
X/ X1/ X2/ Xf Y/ Y1/ Y2/ Z/
$ arr=(*)                     # place objects into array "arr"
$ for i in ${^arr}(N/^F); do printf "$i "; done; echo
X X2 Y Y2 Z

Thus, we can test objects that may already be set in an array parameter.

Note that the code in the for block is, obviously, executed on every directory in turn. If this is not desirable then you can simply populate an array parameter and then operate on that parameter:

$ for i in *(NF) ; do full_directories+=($i) ; done
$ do_something $full_directories

Explanation

For zsh users there is the (F) glob qualifier (see man zshexpn), which matches "full" (non-empty) directories:

$ mkdir X Y
$ touch Y/.f        # Y is now not empty
$ touch f           # create a regular file
$ ls -dF *          # list everything in the current directory
f X/ Y/
$ ls -dF *(F)       # will list only "full" directories
Y/

The qualifier (F) lists objects that match: is a directory AND is not empty. So, (^F) matches: not a directory OR is empty. Thus, (^F) alone would also list regular files, for example. Thus, as explained on the zshexp man page, we also need the (/) glob qualifier, which lists only directories:

$ mkdir X Y Z
$ touch X/f Y/.f    # directories X and Y now not empty
$ for i in *(/^F) ; do echo $i ; done
Z

Thus, to check if a given directory is empty, you can therefore run:

$ mkdir X
$ for i in X(/^F) ; do echo $i ; done ; echo "finished"
X
finished

and just to be sure that a non-empty directory would not be captured:

$ mkdir Y
$ touch Y/.f
$ for i in Y(/^F) ; do echo $i ; done ; echo "finished"
zsh: no matches found: Y(/^F)
finished

Oops! Since Y is not empty, zsh finds no matches for (/^F) ("directories that are empty") and thus spits out an error message saying that no matches for the glob were found. We therefore need to suppress these possible error messages with the (N) glob qualifier:

$ mkdir Y
$ touch Y/.f
$ for i in Y(N/^F) ; do echo $i ; done ; echo "finished"
finished

Thus, for empty directories we need the qualifier (N/^F), which you can read as: "don't warn me about failures, directories that are not full".

Similarly, for non-empty directories we need the qualifier (NF), which we can likewise read as: "don't warn me about failures, full directories".

Tim Siegel
  • 1,171
  • 8
  • 6
Zorawar
  • 6,505
  • 2
  • 23
  • 41
4
# Checks whether a directory contains any nonhidden files.
#
# usage: if isempty "$HOME"; then echo "Welcome home"; fi
#
isempty() {
    for _ief in $1/*; do
        if [ -e "$_ief" ]; then
            return 1
        fi
    done
    return 0
}

Some implementation notes:

  • The for loop avoids a call to an external ls process. It still reads all the directory entries once. This can only be optimized away by writing a C program that uses readdir() explicitly.
  • The test -e inside the loop catches the case of an empty directory, in which case the variable _ief would be assigned the value "somedir/*". Only if that file exists will the function return "nonempty"
  • This function will work in all POSIX implementations. But be aware that the Solaris /bin/sh doesn't fall into that category. Its test implementation doesn't support the -e flag.
Roland Illig
  • 40,703
  • 10
  • 88
  • 121
  • 1
    This would ignore dotfiles in the directory if `dotglob` is not set - `shopt -s dotglob` – l0b0 Sep 11 '12 at 09:19
4

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

directory="/some/dir"
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
  • Can anyone explain me why I was downvoted ? If am writing craps, Id' like to know why ;) – Daishi May 18 '15 at 13:15
  • 2
    I didn't downvote this, but at a guess it's because you're [parsing the output of `ls`](http://mywiki.wooledge.org/ParsingLs). – Toby Speight Jun 04 '15 at 18:26
  • is the linked article unclear? If so, email the author (not me). – Toby Speight Jun 10 '15 at 15:50
  • 1
    @TobySpeight I see the point. But in this case I am counting the lines not enumerating 'em. It should give a false result only if a file name contains a new line. And if file names are containing new lines, something much more important must have f**ked up somewhere ;) – Daishi Jun 16 '15 at 01:46
2
dir_is_empty() {
   [ "${1##*/}" = "*" ]
}

if dir_is_empty /some/dir/* ; then
   echo "huzzah"
fi

Assume you don't have a file named * into /any/dir/you/check, it should work on bash dash posh busybox sh and zsh but (for zsh) require unsetopt nomatch.

Performances should be comparable to any ls which use *(glob), I guess will be slow on directories with many nodes (my /usr/bin with 3000+ files went not that slow), will use at least memory enough to allocate all dirs/filenames (and more) as they are all passed (resolved) to the function as arguments, some shell probably have limits on number of arguments and/or length of arguments.

A portable fast O(1) zero resources way to check if a directory is empty would be nice to have.

update

The version above doesn't account for hidden files/dirs, in case some more test is required, like the is_empty from Rich’s sh (POSIX shell) tricks:

is_empty () (
cd "$1"
set -- .[!.]* ; test -f "$1" && return 1
set -- ..?* ; test -f "$1" && return 1
set -- * ; test -f "$1" && return 1
return 0 )

But, instead, I'm thinking about something like this:

dir_is_empty() {
    [ "$(find "$1" -name "?*" | dd bs=$((${#1}+3)) count=1 2>/dev/null)" = "$1" ]
}

Some concern about trailing slashes differences from the argument and the find output when the dir is empty, and trailing newlines (but this should be easy to handle), sadly on my busybox sh show what is probably a bug on the find -> dd pipe with the output truncated randomically (if I used cat the output is always the same, seems to be dd with the argument count).

Alex
  • 3,264
  • 1
  • 25
  • 40
  • I love the portable solution. I came to give the same answer. I had just written it differently (return 2 if not a directory). Also, these portable solutions have the advantage of not calling any external programs, which might count as a plus for constrained or embedded systems. I'm only worried that using "()" might create a new subprocess (or at least forces to copy environment and stuff and then switch back). Take a look at this: is_empty(){ _d="${1:-.}"; [ ! -d "${_d}" ] && return 2;set -- "${_d}"/* "${_d}"/.[!.]* "${_d}"/..?*; [ "${*}" = "${_d}/* ${_d}/.[!.]* ${_d}/..?*" ]; }; – Diego Augusto Molina Nov 26 '19 at 14:40
  • @DiegoAugustoMolina Recently in a project I had to do this test again, if a directory was empty, at the beginning I used python, then since I practically installed python just for that, I implemented the test in c, the implementation is of an extreme banality , I wonder why it was never added as a test or as a stand-alone command – Alex Nov 26 '19 at 21:48
  • 1
    I too been needing a solution recently to this problem for a (really) constrained system. I even optimized a bit the previous code to use no extra variables at all. Hackish and ugly-looking one-liner but great though. Serve yourself: `is_empty(){ [ ! -d "${1}" ] && return 2;set -- "${1}" "${1}"/* "${1}"/.[!.]* "${1}"/..?*;[ "${*}" = "${1} ${1}/* ${1}/.[!.]* ${1}/..?*" ]; };` – Diego Augusto Molina Nov 27 '19 at 15:17
2

Taking a hint (or several) from olibre's answer, I like a Bash function:

function isEmptyDir {
  [ -d $1 -a -n "$( find $1 -prune -empty 2>/dev/null )" ]
}

Because while it creates one subshell, it's as close to an O(1) solution as I can imagine and giving it a name makes it readable. I can then write

if isEmptyDir somedir
then
  echo somedir is an empty directory
else
  echo somedir does not exist, is not a dir, is unreadable, or is  not empty
fi

As for O(1) there are outlier cases: if a large directory has had all or all but the last entry deleted, "find" may have to read the whole thing to determine whether it's empty. I believe that expected performance is O(1) but worst-case is linear in the directory size. I have not measured this.

ForDummies
  • 151
  • 1
  • 2
  • 9
1

I am surprised the wooledge guide on empty directories hasn't been mentioned. This guide, and all of wooledge really, is a must read for shell type questions.

Of note from that page:

Never try to parse ls output. Even ls -A solutions can break (e.g. on HP-UX, if you are root, ls -A does the exact opposite of what it does if you're not root -- and no, I can't make up something that incredibly stupid).

In fact, one may wish to avoid the direct question altogether. Usually people want to know whether a directory is empty because they want to do something involving the files therein, etc. Look to the larger question. For example, one of these find-based examples may be an appropriate solution:

   # Bourne
   find "$somedir" -type f -exec echo Found unexpected file {} \;
   find "$somedir" -maxdepth 0 -empty -exec echo {} is empty. \;  # GNU/BSD
   find "$somedir" -type d -empty -exec cp /my/configfile {} \;   # GNU/BSD

Most commonly, all that's really needed is something like this:

   # Bourne
   for f in ./*.mpg; do
        test -f "$f" || continue
        mympgviewer "$f"
    done

In other words, the person asking the question may have thought an explicit empty-directory test was needed to avoid an error message like mympgviewer: ./*.mpg: No such file or directory when in fact no such test is required.

bishop
  • 37,830
  • 11
  • 104
  • 139
1

Small variation of Bruno's answer:

files=$(ls -1 /some/dir| wc -l)
if [ $files -gt 0 ] 
then
    echo "Contains files"
else
    echo "Empty"
fi

It works for me

Community
  • 1
  • 1
loockass
  • 38
  • 5
1

With some workaround I could find a simple way to find out whether there are files in a directory. This can extend with more with grep commands to check specifically .xml or .txt files etc. Ex : ls /some/dir | grep xml | wc -l | grep -w "0"

#!/bin/bash
if ([ $(ls /some/dir | wc -l  | grep -w "0") ])
    then
        echo 'No files'
    else
        echo 'Found files'
fi
chanaka777
  • 380
  • 1
  • 2
  • 10
1
if [[ -s somedir ]]; then
    echo "Files present"
fi

In my testing with bash 5.0.17, [[ -s somedir ]] will return true if somedir has any children. The same is true of [ -s somedir ]. Note that this will also return true if there are hidden files or subdirectories. It may also be filesystem-dependent.

Zenexer
  • 18,788
  • 9
  • 71
  • 77
1

It really feels like there should be an option to test for an empty directory. I'll leave that editorial comment as a suggestion to the maintainers of the test command, but the counterpart exists for empty files.

In the trivial use case that brought me here, I'm not worried about looping through a huge number of files, nor am I worried about .files. I was hoping to find the aforementioned "missing" operand to test. C'est la guerre.

In the example below directory empty is empty, and full has files.

$ for f in empty/*; do test -e $f; done
$ echo $?
1
$ for f in full/*; do test -e $f; done
$ echo $?
0

Or, shorter and uglier still, but again only for relatively trivial use cases:

$ echo empty/*| grep \*
$ echo $?
1

$ echo full/* | grep \*
$ echo $?
0
Chris K
  • 31
  • 6
0

So far I haven't seen an answer that uses grep which I think would give a simpler answer (with not too many weird symbols!). Here is how I would check if any files exist in the directory using bourne shell:

this returns the number of files in a directory:

ls -l <directory> | egrep -c "^-"

you can fill in the directory path in where directory is written. The first half of the pipe ensures that the first character of output is "-" for each file. egrep then counts the number of line that start with that symbol using regular expressions. now all you have to do is store the number you obtain and compare it using backquotes like:

 #!/bin/sh 
 fileNum=`ls -l <directory> | egrep -c "^-"`  
 if [ $fileNum == x ] 
 then  
 #do what you want to do
 fi

x is a variable of your choice.

Jecht Tyre
  • 297
  • 2
  • 9
0

Mixing prune things and last answers, I got to

find "$some_dir" -prune -empty -type d | read && echo empty || echo "not empty"

that works for paths with spaces too

Laurent G
  • 397
  • 8
  • 16
0

Simple answer with bash:

if [[ $(ls /some/dir/) ]]; then echo "huzzah"; fi;
Thomas Steinbach
  • 1,019
  • 1
  • 9
  • 19
0

I would go for find:

if [ -z "$(find $dir -maxdepth 1 -type f)" ]; then
    echo "$dir has NO files"
else
    echo "$dir has files"

This checks the output of looking for just files in the directory, without going through the subdirectories. Then it checks the output using the -z option taken from man test:

   -z STRING
          the length of STRING is zero

See some outcomes:

$ mkdir aaa
$ dir="aaa"

Empty dir:

$ [ -z "$(find aaa/ -maxdepth 1 -type f)" ] && echo "empty"
empty

Just dirs in it:

$ mkdir aaa/bbb
$ [ -z "$(find aaa/ -maxdepth 1 -type f)" ] && echo "empty"
empty

A file in the directory:

$ touch aaa/myfile
$ [ -z "$(find aaa/ -maxdepth 1 -type f)" ] && echo "empty"
$ rm aaa/myfile 

A file in a subdirectory:

$ touch aaa/bbb/another_file
$ [ -z "$(find aaa/ -maxdepth 1 -type f)" ] && echo "empty"
empty
fedorqui
  • 275,237
  • 103
  • 548
  • 598
0

In another thread How to test if a directory is empty with find i proposed this

[ "$(cd $dir;echo *)" = "*" ] && echo empty || echo non-empty

With the rationale that, $dir do exist because the question is "Checking from shell script if a directory contains files", and that * even on big dir is not that big, on my system /usr/bin/* is just 12Kb.

Update: Thanx @hh skladby, the fixed one.

[ "$(cd $dir;echo .* *)" = ". .. *" ] && echo empty || echo non-empty
Phi
  • 735
  • 7
  • 22
  • The line of thought is perfect, but you miss dot files. And searching for both dot files and non dot files in a one-liner is the task. – hh skladby Oct 06 '21 at 10:22
  • Ouch :-) ok then may be [ "$(cd $dir;echo .* *)" = ". .. *" ] && echo empty || echo non-empty – Phi Oct 06 '21 at 15:01
0

Without calling utils like ls, find, etc.:

POSIX safe, i.e. not dependent on your Bash / xyz shell / ls / etc. version:

dir="/some/dir"
[ "$(echo $dir/*)x" != "$dir/*x" ] || [ "$(echo $dir/.[^.]*)x" != "$dir/.[^.]*x" ] || echo "empty dir"

The idea:

  • echo * lists non-dot files
  • echo .[^.]* lists dot files except of "." and ".."
  • if echo finds no matches, it returns the search expression, i.e. here * or .[^.]* - which both are no real strings and have to be concatenated with e.g. a letter to coerce a string
  • || alternates the possibilities in a short circuit: there is at least one non-dot file or dir OR at least one dot file or dir OR the directory is empty - on execution level: "if first possibility fails, try next one, if this fails, try next one"; here technically Bash "tries to execute" echo "empty dir", put your action for empty dirs here (eg. exit).

Checked with symlinks, yet to check with more exotic possible file types.

hh skladby
  • 101
  • 6
-1

to test a specific target directory

if [ -d $target_dir ]; then
    ls_contents=$(ls -1 $target_dir | xargs); 
    if [ ! -z "$ls_contents" -a "$ls_contents" != "" ]; then
        echo "is not empty";
    else
        echo "is empty";
    fi;
else
    echo "directory does not exist";
fi;
Ian Kenney
  • 6,376
  • 1
  • 25
  • 44
N D
  • 717
  • 6
  • 10
-1

Try with command find. Specify the directory hardcoded or as argument. Then initiate find to search all files inside the directory. Check if return of find is null. Echo the data of find

#!/bin/bash

_DIR="/home/user/test/"
#_DIR=$1
_FIND=$(find $_DIR -type f )
if [ -n "$_FIND" ]
then
   echo -e "$_DIR contains files or subdirs with files \n\n "
   echo "$_FIND"
else
echo "empty (or does not exist)"
fi
igiannak
  • 104
  • 1
  • 11
  • If the directory has empty directories or non-regular files (sockets, char devices, symlinks, etc.) inside this won't work. The directory would be reported to be empty. – Diego Augusto Molina Nov 26 '19 at 14:30
  • @DiegoAugustoMolina if i understood correctly in the question was that we are looking to check if files exist (as files in literal) thats the reason -f argument was used. but your comments still stands true. – igiannak Nov 27 '19 at 08:25
-1
if ls /some/dir/* >/dev/null 2>&1 ; then echo "huzzah"; fi;
David Webb
  • 190,537
  • 57
  • 313
  • 299
Toby
  • 27
  • 1
-2

Works well for me this (when dir exist):

some_dir="/some/dir with whitespace & other characters/"
if find "`echo "$some_dir"`" -maxdepth 0 -empty | read v; then echo "Empty dir"; fi

With full check:

if [ -d "$some_dir" ]; then
  if find "`echo "$some_dir"`" -maxdepth 0 -empty | read v; then echo "Empty dir"; else "Dir is NOT empty" fi
fi
jerzyjerzy
  • 11
  • 1
-2

I dislike the ls - A solutions posted. Most likely you wish to test if the directory is empty because you don't wish to delete it. The following does that. If however you just wish to log an empty file, surely deleting and recreating it is quicker then listing possibly infinite files?

This should work...

if !  rmdir ${target}
then
    echo "not empty"
else
    echo "empty"
    mkdir ${target}
fi
jjnguy
  • 136,852
  • 53
  • 295
  • 323
thejartender
  • 9,339
  • 6
  • 34
  • 51