linux - How can I restrict a bash find to only specific sub-sub-directories

07
2014-07
  • Guest

    I'm trying to list all the files in a specific sub-directory but different directories which are themselves on a different volume.

    The following works, but only on a fully specific sub-directory (and I've got hundreds of them):
    find "/Volumes/Products/Specific Product Directory/Work Instructions" -print

    What I haven't been able to figure out is how to search across varied sub-directories. So, for example, using the wild character * in place of each specific product directory:
    find "/Volumes/Products/*/Work Instructions" -print // Does not work.

  • Answers
  • Daniel Beck

    The * is only interpreted by the shell when not quoted.

    find "/Volumes/Products/"*"/Work Instructions" -print
    find /Volumes/Products/*/Work\ Instructions -print
    

  • Related Question

    linux - Bash: Find folders with less than x files
  • Leda

    How would I go about finding all the folders in a directory than contain less than x number of .flac files?


  • Related Answers
  • Gilles
    • For every subdirectory, print the subdirectory name if there are at most 42 .flac files in the subdirectory. To execute a command on the directories, replace -print by -exec … \;. POSIX compliant.

      find . -type d -exec sh -c 'set -- "$0"/*.flac; [ $# -le 42 ]' {} \; -print
      

      Note that this command won't work to search for directories containing zero .flac files ("$0/*.flac" expands to at least one word). Instead, use

      find . -type d -exec sh -c 'set -- "$0"/*.flac; ! [ -e "$1" ]' {} \; -print
      
    • Same algorithm in zsh. **/* expands to all the files in the current directory and its subdirectories recursively. **/*(/) restricts the expansion to directories. {.,**/*}(/) adds the current directory. Finally, (e:…:) restricts the expansion to the matches for which the shell code returns 0.

      echo {.,**/*}(/e:'set -- $REPLY/*.flac(N); ((# <= 42))':)
      

      This can be broken down in two steps for legibility.

      few_flacs () { set -- $REPLY/*.flac(N); ((# <= 42)); }
      echo {.,**/*}(/+few_flacs)
      

    Changelog:
    ​• handle x=0 correctly.

  • cYrus

    Replace $MAX with your own limit:

    find -name '*.flac' -printf '%h\n' | sort | uniq -c | while read -r n d ; do [ $n -lt $MAX ] && printf '%s\n' "$d" ; done
    

    Note: This will print all the subdirectories with a number of .flac files between 0 and $MAX (both excluded).