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 by zsh in the early 90s.
  • (D.:t:r) is a glob qualifier, a zsh-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 as find would. Most likely, you'd want to take that one off.
  • .: only regular files (like -type f in find)
  • :t, :r: history modifiers like in csh/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 like rc's x^$array or fish's x$array would do. For instance if $array is (1, 2). That becomes x1 x2.
  • ${(u)array} (for unique), 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\""