linux - find: show directories which contain certain subdirectories

26
2014-06
  • Felipe Alvarez

    I have a list of directories

    /u2/tip/coy/inter/fcs/
    /u2/tip/coy/inter/fcs/devel
    /u2/tip/coy/inter/fcs/ecom_flink
    /u2/tip/coy/inter/fcs/totalstable
    /u2/tip/coy/inter/fcs/develbi
    /u2/tip/coy/inter/fcs/tgn
    /u2/tip/coy/inter/fcs/tdhmdcuat
    /u2/tip/coy/inter/fcs/ecom_tdhmdc
    /u2/tip/coy/inter/fcs/ecom_tdh
    /u2/tip/coy/inter/fcs/grow
    /u2/tip/coy/inter/fcs/sgsb
    /u2/tip/coy/inter/fcs/tdhmdc
    /u2/tip/coy/inter/fcs/ecom_grow
    /u2/tip/coy/inter/fcs/masupport
    /u2/tip/coy/inter/fcs/totalslow
    /u2/tip/coy/inter/fcs/ecom_sgsb
    /u2/tip/coy/inter/fcs/tdh
    

    But only a subset of these contain */out directory:

    /u2/tip/coy/inter/fcs/devel/out
    /u2/tip/coy/inter/fcs/ecom_flink/out
    /u2/tip/coy/inter/fcs/ecom_grow/out
    /u2/tip/coy/inter/fcs/ecom_sgsb/out
    /u2/tip/coy/inter/fcs/ecom_tdhmdc/out
    /u2/tip/coy/inter/fcs/ecom_tdh/out
    /u2/tip/coy/inter/fcs/tdhmdc/out
    /u2/tip/coy/inter/fcs/tdh/out
    

    I wondered if there was a way to use a command (such as find) which, given /u2/tip/coy/inter/fcs, will return this list:

    devel
    ecom_flink
    ecom_grow
    ecom_sgsb
    ecom_tdhmdc
    ecom_tdh
    tdhmdc
    tdh
    

    Without the help of grep or grep-like filters/tools (sed, awk, and friends)

  • Answers
  • stib
    find /u2/tip/coy/inter/fcs -type d -name "out"
    

    returns the subset of folders,

    /u2/tip/coy/inter/fcs/devel/out
    /u2/tip/coy/inter/fcs/ecom_flink/out
    /u2/tip/coy/inter/fcs/ecom_grow/out
    …etc 
    

    you can then run dirname on those results:

    find /u2/tip/coy/inter/fcs -type d -name "out" -exec dirname {} \;
    
    /u2/tip/coy/inter/fcs/devel
    /u2/tip/coy/inter/fcs/ecom_flink
    /u2/tip/coy/inter/fcs/ecom_grow
    …etc
    

    And by using sh -c you can execute basename on that result:

    find /u2/tip/coy/inter/fcs -type d -name "out" -exec sh -c 'basename "$(dirname "$0")"' {} \;
    

    thanks slhck for the above.

    The question is: is running a shell containing a process that works on the output of a subshell containing another process simpler, faster or better than piping the output of find to sed/awk?

  • grumpf
    find /u2/tip/coy/inter/fcs -name 'out' -type d |
    while read line ; do
        IFS='/'
        set -- $line
        num=$(( $# - 1))
        eval  "echo \"\${$num}\""
    done
    

    but this will miserably fail when filename have embedded newlines


  • Related Question

    command line - How to find the executable files under a certain directory in linux?
  • HaiYuan Zhang

    How to find the executable files under a certain directory in linux?


  • Related Answers
  • knittl

    use the -executable option:

    find <dir> -executable
    

    if you want to find only executable files and not searchable directories, combine with -type f:

    find <dir> -executable -type f
    

    EDIT:

    checking with the comments i see there’s no type x. i’m sorry, this was my mistake. checking for executable files can be done with -perm (not recommended) or -executable (recommended, as it takes ACL into account).

  • innaM

    Use the find's -perm option. This will find files in the current directory that are either executable by their owner, by group members or by others:

    find . -perm /u=x,g=x,o=x
    

    Edit:

    I just found another option that is present at least in GNU find 4.4.0:

    find . -executable
    

    This should work even better because ACLs are also considered.

  • AjayKumarBasuthkar

    A file marked executable need not be a executable or loadable file or object.

    Here is what I use:

    find ./ -type f -name "*" -not -name "*.o" -exec sh -c '
        case "$(head -n 1 "$1")" in
          ?ELF*) exit 0;;
          MZ*) exit 0;;
          #!*/ocamlrun*)exit0;;
        esac
    exit 1
    ' sh {} \; -print