2

I have a directory named dir1 which has about 800 sub-directories named disp-001, disp-002, ... disp-800. I need to find sub-directories that

  • either do not contain a file stdout or
  • if they do, that file does not contain a particular string str1.

Identifying sub-directories that do not contain the file is answered in another question

$ find . -type d \! -exec test -e '{}/stdout' \; -print

However if I try to include grep in the above command, it does not work

 $ find . -type d \! -exec test -e 'grep str1 {}/stdout' \; -print

How can I include the string search to return me the directory of interest?

2 Answers 2

4

You can adapt any of the solutions there, e.g.

  • use ( -exec or -exec ) with slm's or patrick's solutions (the second exec is executed only if the first one returns false, -print is executed only if one of them returns true):

    find . -type d \( ! -exec test -f '{}/stdout' \; -o ! -exec grep -q str1 '{}/stdout' \; \) -print
    

    or even shorter as suggested by Costas:

    find . -type d \! -exec grep -q 'str1' {}/stdout 2>/dev/null \; -print
    
  • use a condition with terdon's solution:

    for d in **/
    do
      if [[ ! -f "$d"stdout ]] then
        printf '%s\n' "$d"
      else
        grep -q str1 "$d"stdout || printf '%s\n' "$d"
      fi
    done
    
  • or, with zsh:

    print -rl **/*(/e_'[[ ! -f $REPLY/stdout ]] || ! grep -q str1 $REPLY/stdout'_)
    
2
  • You can avoid extra test find . -type d \! -exec grep -q 'str1' {}/stdout 2>/dev/null \; -print
    – Costas
    Sep 23, 2015 at 20:27
  • @Costas - you're right, I misunderstood the question... I'll edit my answer... Thanks for the heads-up ! Sep 23, 2015 at 20:34
2

To get that list just use grep:

grep -L str1 dir-*/stdout

Where:

  • -L gives only the file without a match.
  • str1 is the string you want to search.
  • And if your files are in the same depth you can use simple wildcards.
    • If not, use the -r flag of grep to search recusively in the directories.

To continue that and work on that list you could pipe it nullbyte-delimited (greps -Z) to a while loop:

grep -LZ str1 dir-*/stdout | while IFS= read -r -d '' f; do
  echo "${f%%/*}" # gives the directory name
done

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .