Portable check empty directory












7















With Bash and Dash, you can check for an empty directory using just the shell
(ignore dotfiles to keep things simple):



set *
if [ -e "$1" ]
then
echo 'not empty'
else
echo 'empty'
fi


However I recently learned that Zsh fails spectacularly in this case:



% set *
zsh: no matches found: *

% echo "$? $#"
1 0


So not only does the set command fail, but it doesn't even set $@. I suppose
I could test if $# is 0, but it appears that Zsh even stops execution:



% { set *; echo 2; }
zsh: no matches found: *


Compare with Bash and Dash:



$ { set *; echo 2; }
2


Can this be done in a way that works in bash, dash and zsh?










share|improve this question

























  • Related: Why is nullglob not default?

    – Stéphane Chazelas
    1 hour ago
















7















With Bash and Dash, you can check for an empty directory using just the shell
(ignore dotfiles to keep things simple):



set *
if [ -e "$1" ]
then
echo 'not empty'
else
echo 'empty'
fi


However I recently learned that Zsh fails spectacularly in this case:



% set *
zsh: no matches found: *

% echo "$? $#"
1 0


So not only does the set command fail, but it doesn't even set $@. I suppose
I could test if $# is 0, but it appears that Zsh even stops execution:



% { set *; echo 2; }
zsh: no matches found: *


Compare with Bash and Dash:



$ { set *; echo 2; }
2


Can this be done in a way that works in bash, dash and zsh?










share|improve this question

























  • Related: Why is nullglob not default?

    – Stéphane Chazelas
    1 hour ago














7












7








7








With Bash and Dash, you can check for an empty directory using just the shell
(ignore dotfiles to keep things simple):



set *
if [ -e "$1" ]
then
echo 'not empty'
else
echo 'empty'
fi


However I recently learned that Zsh fails spectacularly in this case:



% set *
zsh: no matches found: *

% echo "$? $#"
1 0


So not only does the set command fail, but it doesn't even set $@. I suppose
I could test if $# is 0, but it appears that Zsh even stops execution:



% { set *; echo 2; }
zsh: no matches found: *


Compare with Bash and Dash:



$ { set *; echo 2; }
2


Can this be done in a way that works in bash, dash and zsh?










share|improve this question
















With Bash and Dash, you can check for an empty directory using just the shell
(ignore dotfiles to keep things simple):



set *
if [ -e "$1" ]
then
echo 'not empty'
else
echo 'empty'
fi


However I recently learned that Zsh fails spectacularly in this case:



% set *
zsh: no matches found: *

% echo "$? $#"
1 0


So not only does the set command fail, but it doesn't even set $@. I suppose
I could test if $# is 0, but it appears that Zsh even stops execution:



% { set *; echo 2; }
zsh: no matches found: *


Compare with Bash and Dash:



$ { set *; echo 2; }
2


Can this be done in a way that works in bash, dash and zsh?







bash zsh wildcards portability dash






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Jan 7 at 1:28









terdon

129k32253430




129k32253430










asked Jan 7 at 1:06









ThreeThree

362




362













  • Related: Why is nullglob not default?

    – Stéphane Chazelas
    1 hour ago



















  • Related: Why is nullglob not default?

    – Stéphane Chazelas
    1 hour ago

















Related: Why is nullglob not default?

– Stéphane Chazelas
1 hour ago





Related: Why is nullglob not default?

– Stéphane Chazelas
1 hour ago










4 Answers
4






active

oldest

votes


















6














While zsh's default behaviour is to give an error, this is controlled by the nomatch option. You can unset the option to leave the * in place the way that bash and dash do:



setopt -o nonomatch


While that command won't work in either of the others, you can just ignore that:



setopt -o nonomatch 2>/dev/null || true ; set *


This runs setopt on zsh, and suppresses the error output (2>/dev/null) and return code (|| true) of the failed command on the others.



As written it's problematic if there is a file, for example, -e: then you will run set -e and change the shell options to terminate whenever a command fails; there are worse outcomes if you're creative. set -- * will be safer and prevent the option changes.






share|improve this answer

































    2














    Zsh's syntax is not compatible with sh. It's close enough to look like sh, but not close enough that you can take sh code and run it unchanged.



    If you want to run sh code in zsh, for example because you have an sh function or snippet written for sh that you want to use in a zsh script, you can use the emulate builtin. For example, to source a file written for sh in a zsh script:



    emulate sh -c 'source /path/to/file.sh'


    To write a function or script in sh syntax and make it possible to run it in zsh, put this near the beginning:



    emulate -L sh 2>/dev/null || true


    In sh syntax, zsh supports all POSIX constructs (it's about as POSIX compliant as bash --posix or ksh93 or mksh). It also supports some ksh and bash extensions such as arrays (0-indexed in ksh, in bash and under emulate sh, but 1-indexed in native zsh) and [[ … ]]. If you want POSIX sh plus ksh globs, use emulate … ksh … instead of emulate … sh …, and add if [[ -n $BASH ]]; then shopt -s extglob; fi for the sake of bash (note that this is not local to the script/function).



    The native zsh way to enumerate all the entries in a directory except . and .. is



    set -- *(DN)


    This uses the glob qualifiers D to include dot files and N to produce an empty list if there are no matches.



    The native zsh way to enumerate all the entries in a directory except . and .. is a lot more complicated. You need to list dot files, and if you're listing files in the current directory or in a path that isn't guaranteed to be absolute you need take care in case there is a file name that begins with a dash. Here's one way to do it, by using the patterns ..?* .[!.]* * to list all files except . and .. and removing unexpanded patterns.



    set -- ..?*
    if [ "$#" -eq 1 ] && ! [ -e "$1" ] && ! [ -L "$1" ]; then shift; fi
    set -- .[!.]* "$@"
    if [ "$#" -eq 1 ] && ! [ -e "$1" ] && ! [ -L "$1" ]; then shift; fi
    set -- * "$@"
    if [ "$#" -eq 1 ] && ! [ -e "$1" ] && ! [ -L "$1" ]; then shift; fi


    If all you want to do is to test whether a directory is empty, there's a much easier way.



    if ls -A /path/to/directory/ | grep -q '^'; then
    echo "/path/to/directory is not empty"
    else
    echo "/path/to/directory is empty"
    fi





    share|improve this answer


























    • shorter if ls -A | read q; then echo not empty; else echo empty; fi

      – Three
      Jan 13 at 14:25



















    1














    Most portable way would be via set and globstar for all POSIX-compliant shells. This has been shown in Gilles's answer on a related question. I've adapted the method slightly into a function:



    rm -rf empty_dir/
    mkdir empty_dir/
    pwd
    cd empty_dir/
    pwd
    dir_empty(){

    # https://stackoverflow.com/a/9911082/3701431
    if [ -n "$ZSH_VERSION" ]; then
    # https://unix.stackexchange.com/a/310553/85039
    setopt +o nomatch
    fi

    set -- * .*
    echo "$@"
    for i; do
    [ "$i" = "." ] || [ "$i" = ".." ] && continue
    [ -e "$i" ] && echo "Not empty" && return 1
    done
    echo "Empty" && return 0
    }
    dir_empty
    touch '*'
    dir_empty


    The big problem with zsh is that while ksh and bash behave in more or less consistent manner - that is when we do set * .* you will have 3 positional parameters * . .. in really empty directory - in zsh you will get * .* as positional parameters. Luckily at least for i ; do ... done to iterate over positional parameters works consistently. The rest is just iteration and check for existence of the filename, with . and .. skipped.





    Try it online in ksh!



    Try it online in zsh!






    share|improve this answer


























    • @Three I've adapted the answer to check for zsh. Unfortunatelly for us zsh decided to go the weird way instead of similar behavior to bash or other shells, since according to POSIX: "If the pattern does not match any pathnames, the returned number of matched paths is set to 0, and the contents of pglob->gl_pathv are implementation-defined." source

      – Sergiy Kolodyazhnyy
      Jan 7 at 2:25











    • turning nomatch everywhere risks breaking code that assumes the default (and very sensible) setting that sh and bash get wrong, so the change really should be localized only to this function

      – thrig
      Jan 7 at 3:02











    • @thrig Well, considering that so far others haven't found a way to make glob work without nomatch, that's the best we got. We can also toggle it back before function exits, of course. Or we could just abandon shell ways and just use something else, like find for instance.

      – Sergiy Kolodyazhnyy
      Jan 7 at 3:16











    • @Three I've revised the answer again. Probably this is the best I can do, as zsh seems to favor features instead of consistency. Hope this helps somewhat.

      – Sergiy Kolodyazhnyy
      Jan 7 at 3:18











    • @SergiyKolodyazhnyy yes thanks - I would just avoid Zsh totally but its used on Manjaro - maybe I will avoid that too :)

      – Three
      Jan 7 at 3:20



















    1














    There are several problems with that



    set *
    if [ -e "$1" ]
    then
    echo 'not empty'
    else
    echo 'empty'
    fi


    code:




    • if the nullglob option (from zsh but now supported by most other shells) is enabled, set * becomes set which lists all the shell variables (and functions in some shells)

    • if the first non-hidden file has a name that starts with - or +, it will be treated as an option by set. Those two issues can be fixed by using set -- * instead.


    • * expands only non-hidden files, so it's not a test whether the directory is empty or not but whether it contains non-hidden files or not. With some shells, you can use a dotglob or globdot option of play with a FIGNORE special variable to work around that.


    • [ -e "$1" ] tests whether a stat() system call succeeds or not. If the first file a symlink to an inaccessible location, that will return false. You shouldn't need to stat() (not even lstat()) any file to know whether a directory is empty or not, only check that it has some content.


    • * expansion involves opening the current directory, retrieving all the entries, storing all the non-hidden one and sorting them, which is also quite inefficient.


    The most efficient way to check if a directory is non-empty (has any entry other than . and ..) in zsh is with the F glob qualifier (F for full):



    if [ .(NF) ]; then
    echo . is not empty
    fi


    N is the nullglob glob qualifier. So .(NF) expands to . if . is full and nothing otherwise.



    After the lstat() on the directory, if zsh finds it has a link-count greater than 2, then that means it has at least one subdirectory so is not empty, so we don't even need to open that directory. Otherwise, zsh opens the directory, and stops at the first entry that is neither . nor .. without having to read, store nor sort everything.



    With POSIX shells (zsh only behaves (more) POSIXly in sh emulation), it is very awkward to check that a directory is non-empty with globs only.



    One way is with:



    set .[!.]* '.[!.]'[*] .[.]?* [*] *
    if [ "$#$1$2$3$4$5" = '5.[!.]*.[!.][*].[.]?*[*]*' ]; then
    echo empty
    else
    echo not empty
    fi


    The idea is that in POSIX shell (a misfeature introduced by the Bourne shell in the late 70s) when a glob doesn't match, it is left unexpanded. So with set -- * if we get $1 == *, we don't know whether it was because there was no match or whether there was a file called *.



    Your (flawed) approach to work around that was to use [ -e "$1" ]. Here instead, we use set -- [*] *. That allows to disambiguate the two cases, because if there is no file, the above will stay [*] *, and if there is a file called *, that becomes * *. We do something similar for hidden files. That is a bit awkward because of yet another misfeature of the Bourne shell (also fixed by zsh, the Forsyth shell, pdksh and fish) whereby the expansion of .* does include the special (pseudo-)entries . and .. when reported by readdir().



    So to make it work in all those shells, you could do:



    cwd_empty()
    if [ -n "$ZSH_VERSION" ]; then
    eval '! [ .(NF) ]'
    else
    set .[!.]* '.[!.]'[*] .[.]?* [*] *
    [ "$#$1$2$3$4$5" = '5.[!.]*.[!.][*].[.]?*[*]*' ]
    fi




    share

























      Your Answer








      StackExchange.ready(function() {
      var channelOptions = {
      tags: "".split(" "),
      id: "106"
      };
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function() {
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled) {
      StackExchange.using("snippets", function() {
      createEditor();
      });
      }
      else {
      createEditor();
      }
      });

      function createEditor() {
      StackExchange.prepareEditor({
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: false,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: null,
      bindNavPrevention: true,
      postfix: "",
      imageUploader: {
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      },
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      });


      }
      });














      draft saved

      draft discarded


















      StackExchange.ready(
      function () {
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f492912%2fportable-check-empty-directory%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      4 Answers
      4






      active

      oldest

      votes








      4 Answers
      4






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      6














      While zsh's default behaviour is to give an error, this is controlled by the nomatch option. You can unset the option to leave the * in place the way that bash and dash do:



      setopt -o nonomatch


      While that command won't work in either of the others, you can just ignore that:



      setopt -o nonomatch 2>/dev/null || true ; set *


      This runs setopt on zsh, and suppresses the error output (2>/dev/null) and return code (|| true) of the failed command on the others.



      As written it's problematic if there is a file, for example, -e: then you will run set -e and change the shell options to terminate whenever a command fails; there are worse outcomes if you're creative. set -- * will be safer and prevent the option changes.






      share|improve this answer






























        6














        While zsh's default behaviour is to give an error, this is controlled by the nomatch option. You can unset the option to leave the * in place the way that bash and dash do:



        setopt -o nonomatch


        While that command won't work in either of the others, you can just ignore that:



        setopt -o nonomatch 2>/dev/null || true ; set *


        This runs setopt on zsh, and suppresses the error output (2>/dev/null) and return code (|| true) of the failed command on the others.



        As written it's problematic if there is a file, for example, -e: then you will run set -e and change the shell options to terminate whenever a command fails; there are worse outcomes if you're creative. set -- * will be safer and prevent the option changes.






        share|improve this answer




























          6












          6








          6







          While zsh's default behaviour is to give an error, this is controlled by the nomatch option. You can unset the option to leave the * in place the way that bash and dash do:



          setopt -o nonomatch


          While that command won't work in either of the others, you can just ignore that:



          setopt -o nonomatch 2>/dev/null || true ; set *


          This runs setopt on zsh, and suppresses the error output (2>/dev/null) and return code (|| true) of the failed command on the others.



          As written it's problematic if there is a file, for example, -e: then you will run set -e and change the shell options to terminate whenever a command fails; there are worse outcomes if you're creative. set -- * will be safer and prevent the option changes.






          share|improve this answer















          While zsh's default behaviour is to give an error, this is controlled by the nomatch option. You can unset the option to leave the * in place the way that bash and dash do:



          setopt -o nonomatch


          While that command won't work in either of the others, you can just ignore that:



          setopt -o nonomatch 2>/dev/null || true ; set *


          This runs setopt on zsh, and suppresses the error output (2>/dev/null) and return code (|| true) of the failed command on the others.



          As written it's problematic if there is a file, for example, -e: then you will run set -e and change the shell options to terminate whenever a command fails; there are worse outcomes if you're creative. set -- * will be safer and prevent the option changes.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Jan 7 at 2:02

























          answered Jan 7 at 1:55









          Michael HomerMichael Homer

          47.2k8124162




          47.2k8124162

























              2














              Zsh's syntax is not compatible with sh. It's close enough to look like sh, but not close enough that you can take sh code and run it unchanged.



              If you want to run sh code in zsh, for example because you have an sh function or snippet written for sh that you want to use in a zsh script, you can use the emulate builtin. For example, to source a file written for sh in a zsh script:



              emulate sh -c 'source /path/to/file.sh'


              To write a function or script in sh syntax and make it possible to run it in zsh, put this near the beginning:



              emulate -L sh 2>/dev/null || true


              In sh syntax, zsh supports all POSIX constructs (it's about as POSIX compliant as bash --posix or ksh93 or mksh). It also supports some ksh and bash extensions such as arrays (0-indexed in ksh, in bash and under emulate sh, but 1-indexed in native zsh) and [[ … ]]. If you want POSIX sh plus ksh globs, use emulate … ksh … instead of emulate … sh …, and add if [[ -n $BASH ]]; then shopt -s extglob; fi for the sake of bash (note that this is not local to the script/function).



              The native zsh way to enumerate all the entries in a directory except . and .. is



              set -- *(DN)


              This uses the glob qualifiers D to include dot files and N to produce an empty list if there are no matches.



              The native zsh way to enumerate all the entries in a directory except . and .. is a lot more complicated. You need to list dot files, and if you're listing files in the current directory or in a path that isn't guaranteed to be absolute you need take care in case there is a file name that begins with a dash. Here's one way to do it, by using the patterns ..?* .[!.]* * to list all files except . and .. and removing unexpanded patterns.



              set -- ..?*
              if [ "$#" -eq 1 ] && ! [ -e "$1" ] && ! [ -L "$1" ]; then shift; fi
              set -- .[!.]* "$@"
              if [ "$#" -eq 1 ] && ! [ -e "$1" ] && ! [ -L "$1" ]; then shift; fi
              set -- * "$@"
              if [ "$#" -eq 1 ] && ! [ -e "$1" ] && ! [ -L "$1" ]; then shift; fi


              If all you want to do is to test whether a directory is empty, there's a much easier way.



              if ls -A /path/to/directory/ | grep -q '^'; then
              echo "/path/to/directory is not empty"
              else
              echo "/path/to/directory is empty"
              fi





              share|improve this answer


























              • shorter if ls -A | read q; then echo not empty; else echo empty; fi

                – Three
                Jan 13 at 14:25
















              2














              Zsh's syntax is not compatible with sh. It's close enough to look like sh, but not close enough that you can take sh code and run it unchanged.



              If you want to run sh code in zsh, for example because you have an sh function or snippet written for sh that you want to use in a zsh script, you can use the emulate builtin. For example, to source a file written for sh in a zsh script:



              emulate sh -c 'source /path/to/file.sh'


              To write a function or script in sh syntax and make it possible to run it in zsh, put this near the beginning:



              emulate -L sh 2>/dev/null || true


              In sh syntax, zsh supports all POSIX constructs (it's about as POSIX compliant as bash --posix or ksh93 or mksh). It also supports some ksh and bash extensions such as arrays (0-indexed in ksh, in bash and under emulate sh, but 1-indexed in native zsh) and [[ … ]]. If you want POSIX sh plus ksh globs, use emulate … ksh … instead of emulate … sh …, and add if [[ -n $BASH ]]; then shopt -s extglob; fi for the sake of bash (note that this is not local to the script/function).



              The native zsh way to enumerate all the entries in a directory except . and .. is



              set -- *(DN)


              This uses the glob qualifiers D to include dot files and N to produce an empty list if there are no matches.



              The native zsh way to enumerate all the entries in a directory except . and .. is a lot more complicated. You need to list dot files, and if you're listing files in the current directory or in a path that isn't guaranteed to be absolute you need take care in case there is a file name that begins with a dash. Here's one way to do it, by using the patterns ..?* .[!.]* * to list all files except . and .. and removing unexpanded patterns.



              set -- ..?*
              if [ "$#" -eq 1 ] && ! [ -e "$1" ] && ! [ -L "$1" ]; then shift; fi
              set -- .[!.]* "$@"
              if [ "$#" -eq 1 ] && ! [ -e "$1" ] && ! [ -L "$1" ]; then shift; fi
              set -- * "$@"
              if [ "$#" -eq 1 ] && ! [ -e "$1" ] && ! [ -L "$1" ]; then shift; fi


              If all you want to do is to test whether a directory is empty, there's a much easier way.



              if ls -A /path/to/directory/ | grep -q '^'; then
              echo "/path/to/directory is not empty"
              else
              echo "/path/to/directory is empty"
              fi





              share|improve this answer


























              • shorter if ls -A | read q; then echo not empty; else echo empty; fi

                – Three
                Jan 13 at 14:25














              2












              2








              2







              Zsh's syntax is not compatible with sh. It's close enough to look like sh, but not close enough that you can take sh code and run it unchanged.



              If you want to run sh code in zsh, for example because you have an sh function or snippet written for sh that you want to use in a zsh script, you can use the emulate builtin. For example, to source a file written for sh in a zsh script:



              emulate sh -c 'source /path/to/file.sh'


              To write a function or script in sh syntax and make it possible to run it in zsh, put this near the beginning:



              emulate -L sh 2>/dev/null || true


              In sh syntax, zsh supports all POSIX constructs (it's about as POSIX compliant as bash --posix or ksh93 or mksh). It also supports some ksh and bash extensions such as arrays (0-indexed in ksh, in bash and under emulate sh, but 1-indexed in native zsh) and [[ … ]]. If you want POSIX sh plus ksh globs, use emulate … ksh … instead of emulate … sh …, and add if [[ -n $BASH ]]; then shopt -s extglob; fi for the sake of bash (note that this is not local to the script/function).



              The native zsh way to enumerate all the entries in a directory except . and .. is



              set -- *(DN)


              This uses the glob qualifiers D to include dot files and N to produce an empty list if there are no matches.



              The native zsh way to enumerate all the entries in a directory except . and .. is a lot more complicated. You need to list dot files, and if you're listing files in the current directory or in a path that isn't guaranteed to be absolute you need take care in case there is a file name that begins with a dash. Here's one way to do it, by using the patterns ..?* .[!.]* * to list all files except . and .. and removing unexpanded patterns.



              set -- ..?*
              if [ "$#" -eq 1 ] && ! [ -e "$1" ] && ! [ -L "$1" ]; then shift; fi
              set -- .[!.]* "$@"
              if [ "$#" -eq 1 ] && ! [ -e "$1" ] && ! [ -L "$1" ]; then shift; fi
              set -- * "$@"
              if [ "$#" -eq 1 ] && ! [ -e "$1" ] && ! [ -L "$1" ]; then shift; fi


              If all you want to do is to test whether a directory is empty, there's a much easier way.



              if ls -A /path/to/directory/ | grep -q '^'; then
              echo "/path/to/directory is not empty"
              else
              echo "/path/to/directory is empty"
              fi





              share|improve this answer















              Zsh's syntax is not compatible with sh. It's close enough to look like sh, but not close enough that you can take sh code and run it unchanged.



              If you want to run sh code in zsh, for example because you have an sh function or snippet written for sh that you want to use in a zsh script, you can use the emulate builtin. For example, to source a file written for sh in a zsh script:



              emulate sh -c 'source /path/to/file.sh'


              To write a function or script in sh syntax and make it possible to run it in zsh, put this near the beginning:



              emulate -L sh 2>/dev/null || true


              In sh syntax, zsh supports all POSIX constructs (it's about as POSIX compliant as bash --posix or ksh93 or mksh). It also supports some ksh and bash extensions such as arrays (0-indexed in ksh, in bash and under emulate sh, but 1-indexed in native zsh) and [[ … ]]. If you want POSIX sh plus ksh globs, use emulate … ksh … instead of emulate … sh …, and add if [[ -n $BASH ]]; then shopt -s extglob; fi for the sake of bash (note that this is not local to the script/function).



              The native zsh way to enumerate all the entries in a directory except . and .. is



              set -- *(DN)


              This uses the glob qualifiers D to include dot files and N to produce an empty list if there are no matches.



              The native zsh way to enumerate all the entries in a directory except . and .. is a lot more complicated. You need to list dot files, and if you're listing files in the current directory or in a path that isn't guaranteed to be absolute you need take care in case there is a file name that begins with a dash. Here's one way to do it, by using the patterns ..?* .[!.]* * to list all files except . and .. and removing unexpanded patterns.



              set -- ..?*
              if [ "$#" -eq 1 ] && ! [ -e "$1" ] && ! [ -L "$1" ]; then shift; fi
              set -- .[!.]* "$@"
              if [ "$#" -eq 1 ] && ! [ -e "$1" ] && ! [ -L "$1" ]; then shift; fi
              set -- * "$@"
              if [ "$#" -eq 1 ] && ! [ -e "$1" ] && ! [ -L "$1" ]; then shift; fi


              If all you want to do is to test whether a directory is empty, there's a much easier way.



              if ls -A /path/to/directory/ | grep -q '^'; then
              echo "/path/to/directory is not empty"
              else
              echo "/path/to/directory is empty"
              fi






              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited 1 hour ago









              Stéphane Chazelas

              302k56568922




              302k56568922










              answered Jan 13 at 10:35









              GillesGilles

              533k12810721594




              533k12810721594













              • shorter if ls -A | read q; then echo not empty; else echo empty; fi

                – Three
                Jan 13 at 14:25



















              • shorter if ls -A | read q; then echo not empty; else echo empty; fi

                – Three
                Jan 13 at 14:25

















              shorter if ls -A | read q; then echo not empty; else echo empty; fi

              – Three
              Jan 13 at 14:25





              shorter if ls -A | read q; then echo not empty; else echo empty; fi

              – Three
              Jan 13 at 14:25











              1














              Most portable way would be via set and globstar for all POSIX-compliant shells. This has been shown in Gilles's answer on a related question. I've adapted the method slightly into a function:



              rm -rf empty_dir/
              mkdir empty_dir/
              pwd
              cd empty_dir/
              pwd
              dir_empty(){

              # https://stackoverflow.com/a/9911082/3701431
              if [ -n "$ZSH_VERSION" ]; then
              # https://unix.stackexchange.com/a/310553/85039
              setopt +o nomatch
              fi

              set -- * .*
              echo "$@"
              for i; do
              [ "$i" = "." ] || [ "$i" = ".." ] && continue
              [ -e "$i" ] && echo "Not empty" && return 1
              done
              echo "Empty" && return 0
              }
              dir_empty
              touch '*'
              dir_empty


              The big problem with zsh is that while ksh and bash behave in more or less consistent manner - that is when we do set * .* you will have 3 positional parameters * . .. in really empty directory - in zsh you will get * .* as positional parameters. Luckily at least for i ; do ... done to iterate over positional parameters works consistently. The rest is just iteration and check for existence of the filename, with . and .. skipped.





              Try it online in ksh!



              Try it online in zsh!






              share|improve this answer


























              • @Three I've adapted the answer to check for zsh. Unfortunatelly for us zsh decided to go the weird way instead of similar behavior to bash or other shells, since according to POSIX: "If the pattern does not match any pathnames, the returned number of matched paths is set to 0, and the contents of pglob->gl_pathv are implementation-defined." source

                – Sergiy Kolodyazhnyy
                Jan 7 at 2:25











              • turning nomatch everywhere risks breaking code that assumes the default (and very sensible) setting that sh and bash get wrong, so the change really should be localized only to this function

                – thrig
                Jan 7 at 3:02











              • @thrig Well, considering that so far others haven't found a way to make glob work without nomatch, that's the best we got. We can also toggle it back before function exits, of course. Or we could just abandon shell ways and just use something else, like find for instance.

                – Sergiy Kolodyazhnyy
                Jan 7 at 3:16











              • @Three I've revised the answer again. Probably this is the best I can do, as zsh seems to favor features instead of consistency. Hope this helps somewhat.

                – Sergiy Kolodyazhnyy
                Jan 7 at 3:18











              • @SergiyKolodyazhnyy yes thanks - I would just avoid Zsh totally but its used on Manjaro - maybe I will avoid that too :)

                – Three
                Jan 7 at 3:20
















              1














              Most portable way would be via set and globstar for all POSIX-compliant shells. This has been shown in Gilles's answer on a related question. I've adapted the method slightly into a function:



              rm -rf empty_dir/
              mkdir empty_dir/
              pwd
              cd empty_dir/
              pwd
              dir_empty(){

              # https://stackoverflow.com/a/9911082/3701431
              if [ -n "$ZSH_VERSION" ]; then
              # https://unix.stackexchange.com/a/310553/85039
              setopt +o nomatch
              fi

              set -- * .*
              echo "$@"
              for i; do
              [ "$i" = "." ] || [ "$i" = ".." ] && continue
              [ -e "$i" ] && echo "Not empty" && return 1
              done
              echo "Empty" && return 0
              }
              dir_empty
              touch '*'
              dir_empty


              The big problem with zsh is that while ksh and bash behave in more or less consistent manner - that is when we do set * .* you will have 3 positional parameters * . .. in really empty directory - in zsh you will get * .* as positional parameters. Luckily at least for i ; do ... done to iterate over positional parameters works consistently. The rest is just iteration and check for existence of the filename, with . and .. skipped.





              Try it online in ksh!



              Try it online in zsh!






              share|improve this answer


























              • @Three I've adapted the answer to check for zsh. Unfortunatelly for us zsh decided to go the weird way instead of similar behavior to bash or other shells, since according to POSIX: "If the pattern does not match any pathnames, the returned number of matched paths is set to 0, and the contents of pglob->gl_pathv are implementation-defined." source

                – Sergiy Kolodyazhnyy
                Jan 7 at 2:25











              • turning nomatch everywhere risks breaking code that assumes the default (and very sensible) setting that sh and bash get wrong, so the change really should be localized only to this function

                – thrig
                Jan 7 at 3:02











              • @thrig Well, considering that so far others haven't found a way to make glob work without nomatch, that's the best we got. We can also toggle it back before function exits, of course. Or we could just abandon shell ways and just use something else, like find for instance.

                – Sergiy Kolodyazhnyy
                Jan 7 at 3:16











              • @Three I've revised the answer again. Probably this is the best I can do, as zsh seems to favor features instead of consistency. Hope this helps somewhat.

                – Sergiy Kolodyazhnyy
                Jan 7 at 3:18











              • @SergiyKolodyazhnyy yes thanks - I would just avoid Zsh totally but its used on Manjaro - maybe I will avoid that too :)

                – Three
                Jan 7 at 3:20














              1












              1








              1







              Most portable way would be via set and globstar for all POSIX-compliant shells. This has been shown in Gilles's answer on a related question. I've adapted the method slightly into a function:



              rm -rf empty_dir/
              mkdir empty_dir/
              pwd
              cd empty_dir/
              pwd
              dir_empty(){

              # https://stackoverflow.com/a/9911082/3701431
              if [ -n "$ZSH_VERSION" ]; then
              # https://unix.stackexchange.com/a/310553/85039
              setopt +o nomatch
              fi

              set -- * .*
              echo "$@"
              for i; do
              [ "$i" = "." ] || [ "$i" = ".." ] && continue
              [ -e "$i" ] && echo "Not empty" && return 1
              done
              echo "Empty" && return 0
              }
              dir_empty
              touch '*'
              dir_empty


              The big problem with zsh is that while ksh and bash behave in more or less consistent manner - that is when we do set * .* you will have 3 positional parameters * . .. in really empty directory - in zsh you will get * .* as positional parameters. Luckily at least for i ; do ... done to iterate over positional parameters works consistently. The rest is just iteration and check for existence of the filename, with . and .. skipped.





              Try it online in ksh!



              Try it online in zsh!






              share|improve this answer















              Most portable way would be via set and globstar for all POSIX-compliant shells. This has been shown in Gilles's answer on a related question. I've adapted the method slightly into a function:



              rm -rf empty_dir/
              mkdir empty_dir/
              pwd
              cd empty_dir/
              pwd
              dir_empty(){

              # https://stackoverflow.com/a/9911082/3701431
              if [ -n "$ZSH_VERSION" ]; then
              # https://unix.stackexchange.com/a/310553/85039
              setopt +o nomatch
              fi

              set -- * .*
              echo "$@"
              for i; do
              [ "$i" = "." ] || [ "$i" = ".." ] && continue
              [ -e "$i" ] && echo "Not empty" && return 1
              done
              echo "Empty" && return 0
              }
              dir_empty
              touch '*'
              dir_empty


              The big problem with zsh is that while ksh and bash behave in more or less consistent manner - that is when we do set * .* you will have 3 positional parameters * . .. in really empty directory - in zsh you will get * .* as positional parameters. Luckily at least for i ; do ... done to iterate over positional parameters works consistently. The rest is just iteration and check for existence of the filename, with . and .. skipped.





              Try it online in ksh!



              Try it online in zsh!







              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited Jan 7 at 3:13

























              answered Jan 7 at 2:02









              Sergiy KolodyazhnyySergiy Kolodyazhnyy

              9,52722659




              9,52722659













              • @Three I've adapted the answer to check for zsh. Unfortunatelly for us zsh decided to go the weird way instead of similar behavior to bash or other shells, since according to POSIX: "If the pattern does not match any pathnames, the returned number of matched paths is set to 0, and the contents of pglob->gl_pathv are implementation-defined." source

                – Sergiy Kolodyazhnyy
                Jan 7 at 2:25











              • turning nomatch everywhere risks breaking code that assumes the default (and very sensible) setting that sh and bash get wrong, so the change really should be localized only to this function

                – thrig
                Jan 7 at 3:02











              • @thrig Well, considering that so far others haven't found a way to make glob work without nomatch, that's the best we got. We can also toggle it back before function exits, of course. Or we could just abandon shell ways and just use something else, like find for instance.

                – Sergiy Kolodyazhnyy
                Jan 7 at 3:16











              • @Three I've revised the answer again. Probably this is the best I can do, as zsh seems to favor features instead of consistency. Hope this helps somewhat.

                – Sergiy Kolodyazhnyy
                Jan 7 at 3:18











              • @SergiyKolodyazhnyy yes thanks - I would just avoid Zsh totally but its used on Manjaro - maybe I will avoid that too :)

                – Three
                Jan 7 at 3:20



















              • @Three I've adapted the answer to check for zsh. Unfortunatelly for us zsh decided to go the weird way instead of similar behavior to bash or other shells, since according to POSIX: "If the pattern does not match any pathnames, the returned number of matched paths is set to 0, and the contents of pglob->gl_pathv are implementation-defined." source

                – Sergiy Kolodyazhnyy
                Jan 7 at 2:25











              • turning nomatch everywhere risks breaking code that assumes the default (and very sensible) setting that sh and bash get wrong, so the change really should be localized only to this function

                – thrig
                Jan 7 at 3:02











              • @thrig Well, considering that so far others haven't found a way to make glob work without nomatch, that's the best we got. We can also toggle it back before function exits, of course. Or we could just abandon shell ways and just use something else, like find for instance.

                – Sergiy Kolodyazhnyy
                Jan 7 at 3:16











              • @Three I've revised the answer again. Probably this is the best I can do, as zsh seems to favor features instead of consistency. Hope this helps somewhat.

                – Sergiy Kolodyazhnyy
                Jan 7 at 3:18











              • @SergiyKolodyazhnyy yes thanks - I would just avoid Zsh totally but its used on Manjaro - maybe I will avoid that too :)

                – Three
                Jan 7 at 3:20

















              @Three I've adapted the answer to check for zsh. Unfortunatelly for us zsh decided to go the weird way instead of similar behavior to bash or other shells, since according to POSIX: "If the pattern does not match any pathnames, the returned number of matched paths is set to 0, and the contents of pglob->gl_pathv are implementation-defined." source

              – Sergiy Kolodyazhnyy
              Jan 7 at 2:25





              @Three I've adapted the answer to check for zsh. Unfortunatelly for us zsh decided to go the weird way instead of similar behavior to bash or other shells, since according to POSIX: "If the pattern does not match any pathnames, the returned number of matched paths is set to 0, and the contents of pglob->gl_pathv are implementation-defined." source

              – Sergiy Kolodyazhnyy
              Jan 7 at 2:25













              turning nomatch everywhere risks breaking code that assumes the default (and very sensible) setting that sh and bash get wrong, so the change really should be localized only to this function

              – thrig
              Jan 7 at 3:02





              turning nomatch everywhere risks breaking code that assumes the default (and very sensible) setting that sh and bash get wrong, so the change really should be localized only to this function

              – thrig
              Jan 7 at 3:02













              @thrig Well, considering that so far others haven't found a way to make glob work without nomatch, that's the best we got. We can also toggle it back before function exits, of course. Or we could just abandon shell ways and just use something else, like find for instance.

              – Sergiy Kolodyazhnyy
              Jan 7 at 3:16





              @thrig Well, considering that so far others haven't found a way to make glob work without nomatch, that's the best we got. We can also toggle it back before function exits, of course. Or we could just abandon shell ways and just use something else, like find for instance.

              – Sergiy Kolodyazhnyy
              Jan 7 at 3:16













              @Three I've revised the answer again. Probably this is the best I can do, as zsh seems to favor features instead of consistency. Hope this helps somewhat.

              – Sergiy Kolodyazhnyy
              Jan 7 at 3:18





              @Three I've revised the answer again. Probably this is the best I can do, as zsh seems to favor features instead of consistency. Hope this helps somewhat.

              – Sergiy Kolodyazhnyy
              Jan 7 at 3:18













              @SergiyKolodyazhnyy yes thanks - I would just avoid Zsh totally but its used on Manjaro - maybe I will avoid that too :)

              – Three
              Jan 7 at 3:20





              @SergiyKolodyazhnyy yes thanks - I would just avoid Zsh totally but its used on Manjaro - maybe I will avoid that too :)

              – Three
              Jan 7 at 3:20











              1














              There are several problems with that



              set *
              if [ -e "$1" ]
              then
              echo 'not empty'
              else
              echo 'empty'
              fi


              code:




              • if the nullglob option (from zsh but now supported by most other shells) is enabled, set * becomes set which lists all the shell variables (and functions in some shells)

              • if the first non-hidden file has a name that starts with - or +, it will be treated as an option by set. Those two issues can be fixed by using set -- * instead.


              • * expands only non-hidden files, so it's not a test whether the directory is empty or not but whether it contains non-hidden files or not. With some shells, you can use a dotglob or globdot option of play with a FIGNORE special variable to work around that.


              • [ -e "$1" ] tests whether a stat() system call succeeds or not. If the first file a symlink to an inaccessible location, that will return false. You shouldn't need to stat() (not even lstat()) any file to know whether a directory is empty or not, only check that it has some content.


              • * expansion involves opening the current directory, retrieving all the entries, storing all the non-hidden one and sorting them, which is also quite inefficient.


              The most efficient way to check if a directory is non-empty (has any entry other than . and ..) in zsh is with the F glob qualifier (F for full):



              if [ .(NF) ]; then
              echo . is not empty
              fi


              N is the nullglob glob qualifier. So .(NF) expands to . if . is full and nothing otherwise.



              After the lstat() on the directory, if zsh finds it has a link-count greater than 2, then that means it has at least one subdirectory so is not empty, so we don't even need to open that directory. Otherwise, zsh opens the directory, and stops at the first entry that is neither . nor .. without having to read, store nor sort everything.



              With POSIX shells (zsh only behaves (more) POSIXly in sh emulation), it is very awkward to check that a directory is non-empty with globs only.



              One way is with:



              set .[!.]* '.[!.]'[*] .[.]?* [*] *
              if [ "$#$1$2$3$4$5" = '5.[!.]*.[!.][*].[.]?*[*]*' ]; then
              echo empty
              else
              echo not empty
              fi


              The idea is that in POSIX shell (a misfeature introduced by the Bourne shell in the late 70s) when a glob doesn't match, it is left unexpanded. So with set -- * if we get $1 == *, we don't know whether it was because there was no match or whether there was a file called *.



              Your (flawed) approach to work around that was to use [ -e "$1" ]. Here instead, we use set -- [*] *. That allows to disambiguate the two cases, because if there is no file, the above will stay [*] *, and if there is a file called *, that becomes * *. We do something similar for hidden files. That is a bit awkward because of yet another misfeature of the Bourne shell (also fixed by zsh, the Forsyth shell, pdksh and fish) whereby the expansion of .* does include the special (pseudo-)entries . and .. when reported by readdir().



              So to make it work in all those shells, you could do:



              cwd_empty()
              if [ -n "$ZSH_VERSION" ]; then
              eval '! [ .(NF) ]'
              else
              set .[!.]* '.[!.]'[*] .[.]?* [*] *
              [ "$#$1$2$3$4$5" = '5.[!.]*.[!.][*].[.]?*[*]*' ]
              fi




              share






























                1














                There are several problems with that



                set *
                if [ -e "$1" ]
                then
                echo 'not empty'
                else
                echo 'empty'
                fi


                code:




                • if the nullglob option (from zsh but now supported by most other shells) is enabled, set * becomes set which lists all the shell variables (and functions in some shells)

                • if the first non-hidden file has a name that starts with - or +, it will be treated as an option by set. Those two issues can be fixed by using set -- * instead.


                • * expands only non-hidden files, so it's not a test whether the directory is empty or not but whether it contains non-hidden files or not. With some shells, you can use a dotglob or globdot option of play with a FIGNORE special variable to work around that.


                • [ -e "$1" ] tests whether a stat() system call succeeds or not. If the first file a symlink to an inaccessible location, that will return false. You shouldn't need to stat() (not even lstat()) any file to know whether a directory is empty or not, only check that it has some content.


                • * expansion involves opening the current directory, retrieving all the entries, storing all the non-hidden one and sorting them, which is also quite inefficient.


                The most efficient way to check if a directory is non-empty (has any entry other than . and ..) in zsh is with the F glob qualifier (F for full):



                if [ .(NF) ]; then
                echo . is not empty
                fi


                N is the nullglob glob qualifier. So .(NF) expands to . if . is full and nothing otherwise.



                After the lstat() on the directory, if zsh finds it has a link-count greater than 2, then that means it has at least one subdirectory so is not empty, so we don't even need to open that directory. Otherwise, zsh opens the directory, and stops at the first entry that is neither . nor .. without having to read, store nor sort everything.



                With POSIX shells (zsh only behaves (more) POSIXly in sh emulation), it is very awkward to check that a directory is non-empty with globs only.



                One way is with:



                set .[!.]* '.[!.]'[*] .[.]?* [*] *
                if [ "$#$1$2$3$4$5" = '5.[!.]*.[!.][*].[.]?*[*]*' ]; then
                echo empty
                else
                echo not empty
                fi


                The idea is that in POSIX shell (a misfeature introduced by the Bourne shell in the late 70s) when a glob doesn't match, it is left unexpanded. So with set -- * if we get $1 == *, we don't know whether it was because there was no match or whether there was a file called *.



                Your (flawed) approach to work around that was to use [ -e "$1" ]. Here instead, we use set -- [*] *. That allows to disambiguate the two cases, because if there is no file, the above will stay [*] *, and if there is a file called *, that becomes * *. We do something similar for hidden files. That is a bit awkward because of yet another misfeature of the Bourne shell (also fixed by zsh, the Forsyth shell, pdksh and fish) whereby the expansion of .* does include the special (pseudo-)entries . and .. when reported by readdir().



                So to make it work in all those shells, you could do:



                cwd_empty()
                if [ -n "$ZSH_VERSION" ]; then
                eval '! [ .(NF) ]'
                else
                set .[!.]* '.[!.]'[*] .[.]?* [*] *
                [ "$#$1$2$3$4$5" = '5.[!.]*.[!.][*].[.]?*[*]*' ]
                fi




                share




























                  1












                  1








                  1







                  There are several problems with that



                  set *
                  if [ -e "$1" ]
                  then
                  echo 'not empty'
                  else
                  echo 'empty'
                  fi


                  code:




                  • if the nullglob option (from zsh but now supported by most other shells) is enabled, set * becomes set which lists all the shell variables (and functions in some shells)

                  • if the first non-hidden file has a name that starts with - or +, it will be treated as an option by set. Those two issues can be fixed by using set -- * instead.


                  • * expands only non-hidden files, so it's not a test whether the directory is empty or not but whether it contains non-hidden files or not. With some shells, you can use a dotglob or globdot option of play with a FIGNORE special variable to work around that.


                  • [ -e "$1" ] tests whether a stat() system call succeeds or not. If the first file a symlink to an inaccessible location, that will return false. You shouldn't need to stat() (not even lstat()) any file to know whether a directory is empty or not, only check that it has some content.


                  • * expansion involves opening the current directory, retrieving all the entries, storing all the non-hidden one and sorting them, which is also quite inefficient.


                  The most efficient way to check if a directory is non-empty (has any entry other than . and ..) in zsh is with the F glob qualifier (F for full):



                  if [ .(NF) ]; then
                  echo . is not empty
                  fi


                  N is the nullglob glob qualifier. So .(NF) expands to . if . is full and nothing otherwise.



                  After the lstat() on the directory, if zsh finds it has a link-count greater than 2, then that means it has at least one subdirectory so is not empty, so we don't even need to open that directory. Otherwise, zsh opens the directory, and stops at the first entry that is neither . nor .. without having to read, store nor sort everything.



                  With POSIX shells (zsh only behaves (more) POSIXly in sh emulation), it is very awkward to check that a directory is non-empty with globs only.



                  One way is with:



                  set .[!.]* '.[!.]'[*] .[.]?* [*] *
                  if [ "$#$1$2$3$4$5" = '5.[!.]*.[!.][*].[.]?*[*]*' ]; then
                  echo empty
                  else
                  echo not empty
                  fi


                  The idea is that in POSIX shell (a misfeature introduced by the Bourne shell in the late 70s) when a glob doesn't match, it is left unexpanded. So with set -- * if we get $1 == *, we don't know whether it was because there was no match or whether there was a file called *.



                  Your (flawed) approach to work around that was to use [ -e "$1" ]. Here instead, we use set -- [*] *. That allows to disambiguate the two cases, because if there is no file, the above will stay [*] *, and if there is a file called *, that becomes * *. We do something similar for hidden files. That is a bit awkward because of yet another misfeature of the Bourne shell (also fixed by zsh, the Forsyth shell, pdksh and fish) whereby the expansion of .* does include the special (pseudo-)entries . and .. when reported by readdir().



                  So to make it work in all those shells, you could do:



                  cwd_empty()
                  if [ -n "$ZSH_VERSION" ]; then
                  eval '! [ .(NF) ]'
                  else
                  set .[!.]* '.[!.]'[*] .[.]?* [*] *
                  [ "$#$1$2$3$4$5" = '5.[!.]*.[!.][*].[.]?*[*]*' ]
                  fi




                  share















                  There are several problems with that



                  set *
                  if [ -e "$1" ]
                  then
                  echo 'not empty'
                  else
                  echo 'empty'
                  fi


                  code:




                  • if the nullglob option (from zsh but now supported by most other shells) is enabled, set * becomes set which lists all the shell variables (and functions in some shells)

                  • if the first non-hidden file has a name that starts with - or +, it will be treated as an option by set. Those two issues can be fixed by using set -- * instead.


                  • * expands only non-hidden files, so it's not a test whether the directory is empty or not but whether it contains non-hidden files or not. With some shells, you can use a dotglob or globdot option of play with a FIGNORE special variable to work around that.


                  • [ -e "$1" ] tests whether a stat() system call succeeds or not. If the first file a symlink to an inaccessible location, that will return false. You shouldn't need to stat() (not even lstat()) any file to know whether a directory is empty or not, only check that it has some content.


                  • * expansion involves opening the current directory, retrieving all the entries, storing all the non-hidden one and sorting them, which is also quite inefficient.


                  The most efficient way to check if a directory is non-empty (has any entry other than . and ..) in zsh is with the F glob qualifier (F for full):



                  if [ .(NF) ]; then
                  echo . is not empty
                  fi


                  N is the nullglob glob qualifier. So .(NF) expands to . if . is full and nothing otherwise.



                  After the lstat() on the directory, if zsh finds it has a link-count greater than 2, then that means it has at least one subdirectory so is not empty, so we don't even need to open that directory. Otherwise, zsh opens the directory, and stops at the first entry that is neither . nor .. without having to read, store nor sort everything.



                  With POSIX shells (zsh only behaves (more) POSIXly in sh emulation), it is very awkward to check that a directory is non-empty with globs only.



                  One way is with:



                  set .[!.]* '.[!.]'[*] .[.]?* [*] *
                  if [ "$#$1$2$3$4$5" = '5.[!.]*.[!.][*].[.]?*[*]*' ]; then
                  echo empty
                  else
                  echo not empty
                  fi


                  The idea is that in POSIX shell (a misfeature introduced by the Bourne shell in the late 70s) when a glob doesn't match, it is left unexpanded. So with set -- * if we get $1 == *, we don't know whether it was because there was no match or whether there was a file called *.



                  Your (flawed) approach to work around that was to use [ -e "$1" ]. Here instead, we use set -- [*] *. That allows to disambiguate the two cases, because if there is no file, the above will stay [*] *, and if there is a file called *, that becomes * *. We do something similar for hidden files. That is a bit awkward because of yet another misfeature of the Bourne shell (also fixed by zsh, the Forsyth shell, pdksh and fish) whereby the expansion of .* does include the special (pseudo-)entries . and .. when reported by readdir().



                  So to make it work in all those shells, you could do:



                  cwd_empty()
                  if [ -n "$ZSH_VERSION" ]; then
                  eval '! [ .(NF) ]'
                  else
                  set .[!.]* '.[!.]'[*] .[.]?* [*] *
                  [ "$#$1$2$3$4$5" = '5.[!.]*.[!.][*].[.]?*[*]*' ]
                  fi





                  share













                  share


                  share








                  edited 27 secs ago

























                  answered 5 mins ago









                  Stéphane ChazelasStéphane Chazelas

                  302k56568922




                  302k56568922






























                      draft saved

                      draft discarded




















































                      Thanks for contributing an answer to Unix & Linux Stack Exchange!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f492912%2fportable-check-empty-directory%23new-answer', 'question_page');
                      }
                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      Histoire des bourses de valeurs

                      Why is there Russian traffic in my log files?

                      Rename multiple files to decrement number in file name?