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 containiningmystring
(basically: don't list dirs containing no yaml files at all).Hope that makes sense.