2217
Comment: put bash solutions at top, removed bash-specific non-array solution (what's wrong with arrays?), removed ls -A solutions (if you want to not use a specific shell you may as well TRY to be portable)
|
3173
|
Deletions are marked like this. | Additions are marked like this. |
Line 1: | Line 1: |
[[Anchor(faq4)]] | <<Anchor(faq4)>> |
Line 3: | Line 3: |
''I just deleted three completely '''wrong''' answers from this question. Please, people, make sure that when you add to the FAQ, your answers'' * answer the question that was asked, and * actually '''work''' ''Thanks. -- GreyCat'' In BASH, you can do this safely and easily with the nullglob option (which changes the behaviour of [:glob:globbing]), and arrays: |
In Bash, you can do this safely and easily with the `nullglob` and `dotglob` options (which change the behaviour of [[glob|globbing]]), and [[BashFAQ/005|arrays]]: |
Line 11: | Line 6: |
shopt -s nullglob | # Bash shopt -s nullglob dotglob |
Line 14: | Line 10: |
shopt -u nullglob | shopt -u nullglob dotglob |
Line 16: | Line 12: |
As you can see we unset the nullglob after using it, to prevent it affecting other globs in the script in unexpected ways. `nullglob` also simplifies various other operations: |
Or you can pour it into a SubShell to avoid having to reset (in fact, unset! - the code above assumes the shell options were unset before) the shell options again: |
Line 20: | Line 15: |
shopt -s nullglob for i in *.zip; do blah blah "$i" # No need to check $i is a file. done shopt -u nullglob |
# Bash if (shopt -s nullglob dotglob; f=(*); ((! ${#f[@]}))); then echo "The current directory is empty." fi |
Line 26: | Line 20: |
Of course, you can use any glob you like instead of `*`. E.g. `*.mpg` or `/my/music/*.mpg` works fine. | |
Line 27: | Line 22: |
Without the {{{nullglob}}}, that would have to be: | Some people dislike `nullglob` because having unmatched globs vanish altogether confuses programs like `ls`. Mistyping `ls *.zip` as `ls *.zpi` may cause every file to be displayed. Setting `nullglob` in a SubShell avoids accidentally changing its setting in the rest of the shell, at the price of an extra `fork()`. If your script needs to run with various non-Bash shell implementations, you can try using an external program like python, perl, or find; or you can try one of these: |
Line 30: | Line 27: |
for i in *.zip; do [[ -f $i ]] || continue # If no .zip files, i becomes *.zip blah blah "$i" done |
# POSIX # Clobbers the positional parameters, so make sure you don't need them. set -- * if test -e "$1" || test -L "$1"; then echo "directory is non-empty" fi |
Line 35: | Line 34: |
(You may want to use the latter anyway, if there's a possibility that the glob may match directories in addition to files.) In fact, you 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 [:UsingFind:find-based examples] may be an appropriate solution: |
(The `-L` test is required because `-e` fails if the first file is a [[BashFAQ/097|dangling symlink]].) |
Line 41: | Line 37: |
# Bourne # (Of course, the system must have printf(1).) if test "`printf '%s %s %s' .* *`" = '. .. *' && test ! -f '*' then echo "directory is empty" fi }}} Yes, they're quite ugly, but they should be more portable than anything depending on [[ParsingLs|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, you 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 [[UsingFind|find-based examples]] may be an appropriate solution: {{{ # Bourne |
|
Line 45: | Line 54: |
If your script needs to run with various shell implementations, you can try using an external program like python, perl, or find as indicated above, or you can try something like: |
Most commonly, all that's really needed is something like this: |
Line 49: | Line 57: |
if [ "`printf %s foo/*`" = 'foo/*' ] && [ ! -e 'foo/*' ] then echo "foo is empty" fi |
# Bourne for f in ./*.mpg; do test -f "$f" || continue mympgviewer "$f" done |
Line 54: | Line 63: |
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. | |
Line 55: | Line 65: |
Yes, it's ugly, but it should be more portable than anything depending on ls output. | ---- CategoryShell |
How can I check whether a directory is empty or not? How do I check for any *.mpg files?
In Bash, you can do this safely and easily with the nullglob and dotglob options (which change the behaviour of globbing), and arrays:
# Bash shopt -s nullglob dotglob files=(*) (( ${#files[*]} )) || echo directory is empty shopt -u nullglob dotglob
Or you can pour it into a SubShell to avoid having to reset (in fact, unset! - the code above assumes the shell options were unset before) the shell options again:
# Bash if (shopt -s nullglob dotglob; f=(*); ((! ${#f[@]}))); then echo "The current directory is empty." fi
Of course, you can use any glob you like instead of *. E.g. *.mpg or /my/music/*.mpg works fine.
Some people dislike nullglob because having unmatched globs vanish altogether confuses programs like ls. Mistyping ls *.zip as ls *.zpi may cause every file to be displayed. Setting nullglob in a SubShell avoids accidentally changing its setting in the rest of the shell, at the price of an extra fork().
If your script needs to run with various non-Bash shell implementations, you can try using an external program like python, perl, or find; or you can try one of these:
# POSIX # Clobbers the positional parameters, so make sure you don't need them. set -- * if test -e "$1" || test -L "$1"; then echo "directory is non-empty" fi
(The -L test is required because -e fails if the first file is a dangling symlink.)
# Bourne # (Of course, the system must have printf(1).) if test "`printf '%s %s %s' .* *`" = '. .. *' && test ! -f '*' then echo "directory is empty" fi
Yes, they're quite ugly, but they should be more portable than anything depending on 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, you 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.