Home > database >  How do I find name of sub directory which does not have any files containing string with shell?
How do I find name of sub directory which does not have any files containing string with shell?

Time:03-18

I have a parent folder consist of many children sub-directories. In each sub-directory, there are(is) several config file(s).

Parent
  |-ChildA - (conf1.yaml, conf2.yaml, foo.yaml)
  |-ChildB - (bar.yaml)
  |-ChildC - (conf2.yaml, foo.yaml, bar.yaml)
  |-ChildD - // if there is GrandChild directory, there is no file.
      |-GrandChildA - (confA.yaml, conf1.yml, foo.yml)
      |-GrandChildB - (confB.yaml, bar.yml)
      |-GrandChildC - (hello.yaml, conf5.yml, foo.yml)
      |-GrandChildD - (world.yaml, conf10.yml)
  |-ChildE - (conf1.yaml, conf2.yaml)
  ....

Even if names of yaml files are same, contents may be different. I want to find out the name of directory which does not contain the string pattern in yaml file. For example, I am looking for the string pattern, overflow and ChildA/conf1.yaml and GrandChildC/hell.yaml contains this string pattern, then I want to have output,

ChildB, ChildC, GrandChildA, GrandChildB, GrandChildD, ChildE // don't mind its format, array, json 

I was thinking to use grep with its option, but it returns, name of file, not name of directory. How can I get name of directory which does not have any files containing pattern string?

EDIT
I think my explanation was kinda unclear. My ultimate goal is,

  • If any file in the directory contains pattern, do not print out directory name
  • If all files in the directory do not contains the pattern string, then print out directory name

CodePudding user response:

(
  # list of possible directories
  find Parent -type f -name '*.yaml' -print0 |\
  xargs -0 dirname |\
  sort | uniq

  # list of unwanted directories (may contain duplicates)
  find Parent -type f -name '*.yaml' -print0 |\
  xargs -0 grep -l overflow |\
  xargs -r dirname

  # uniq -u will remove anything that appears in both lists
) | sort | uniq -u

CodePudding user response:

Using GNU tools for their null delimiter flags (so that filenames containing new lines won't break it).

# find .yaml files containing "mypattern"
find /parent/dir -type f -name '*.yaml' -exec grep -Zl mypattern {}   |

# get parent dir names of matching files
xargs -0 -- dirname -z -- |
sort -zu |

# compare this list against all dirs, printing non matches
grep -Fvxzf - <(find /parent/dir -type d -print0)
  • Final output is new line delimited, add -Z to the last grep for null delimited output. In GNU grep, -z = null delimited input, -Z null delimited output.

  • You could replace second find with find /parent/dir -type f -name '*.yaml' -exec dirname -z -- {} | sort -zu to only compare dirs which actually contain yaml files.

  • ie. list those containing yaml, but not yaml which has mypattern; as opposed to listing every dir which doesn't have yaml containining mystring (basically: don't list dirs containing no yaml files at all).

  • Hope that makes sense.

  • Related