Piping from a find into grep
With zsh
:
projects=(server/lib/**/*(D.:t:r))
grep -rFl --exclude-dir=node_modules -e${(u)^projects} .
**/
recursive globbing. A feature introduced byzsh
in the early 90s.(D.:t:r)
is a glob qualifier, azsh
-specific feature that allows selecting files using attributes other than name, or change the sorting or do modifications on the found files.D
: include dot-files and traverse dot-dirs asfind
would. Most likely, you'd want to take that one off..
: only regular files (like-type f
infind
):t
,:r
: history modifiers like incsh
/bash
but here applied to the globbed files.:t
for the tail (basename),:r
for the root name (extension removed).x${^array}
distributes the elements likerc
'sx^$array
orfish
'sx$array
would do. For instance if$array
is (1
,2
). That becomesx1
x2
.${(u)array}
(foru
nique), remove duplicates ((u)
being a parameter expansion flag).
For the list of files that contain none of the strings, replace -l
with -L
(assuming GNU grep
, but you're already using GNU-specific options here). -F
is for fixed string search (as you probably don't want those project names to be treated as regexps). You may also want to throw in a -w
option to grep
for word match so that foo
doesn't match in foobar
for instance (would still match in foo-bar
though).
Short answer:
If you just want to pass a bunch of lines as arguments to another command, xargs
is your friend - in this case, because you're putting it into the middle of a command, you'll want to use the -I {}
flag. This sets {}
as a placeholder so that you can put wherever (you can set your own placeholder, but I usually stick to {}
since it won't be mistaken for many other things.
Putting it all together (assuming the commands you've given do what you think they do!):
find server/lib -type f -exec basename {} \; | cut -f 1 -d '.' | xargs -I {} grep -R --exclude-dir=node_modules {} . -l
Long answer
Ok, so we can probably take this further. Let's say you wanted the format you mentioned earlier - you can xargs
to sh -c
so you can chain commands:
find server/lib -type f -exec basename {} \; | cut -f 1 -d '.' | xargs -I {} sh -c "echo {}; grep -R --exclude-dir=node_modules {} . -l"
Running this on my machine, it looks like this is giving you the files where the file is found. My brain is tired, so instead of wrapping it in a nice script (which is what you should actually do when oneliners start to get gnarly, and use https://www.shellcheck.net/ while you're at it) you can have this horrible hack instead, which (I think) will give you the output you're looking for:
find server/lib -type f -exec basename {} \; | cut -f 1 -d '.' | xargs -I {} sh -c "echo {}; grep -R --exclude-dir=node_modules {} . -l && printf \"\n\" || printf \"Not found\n\n\""