grep -l Into xargs: Act on Matching Files
grep -l lists the files that contain a pattern, and xargs runs a command on each of them.
A common bulk-edit pattern is "find every file mentioning X and do Y to it". grep -l finds them; xargs applies the action.
What it does
grep -rl <pattern> prints the names of files that contain at least one match, one per line. Piped into xargs, those names become arguments to your command. For safety with odd filenames, grep -rlZ emits NUL-terminated names to pair with xargs -0.
Common usage
# replace a string in every file that contains it
grep -rlZ 'OLD_API' . | xargs -0 -r sed -i 's/OLD_API/NEW_API/g'
# count lines in every file mentioning TODO
grep -rl TODO src | xargs wc -lOptions
| Flag | What it does |
|---|---|
| grep -l | Print only names of files with a match |
| grep -r | Recurse into directories |
| grep -Z | NUL-terminate the filenames (pair with xargs -0) |
| xargs -0 | Read those NUL-terminated names safely |
| xargs -r | Do nothing if grep found no files |
In CI
Add -r to xargs so an empty grep result does not run sed (or your command) with no files. Use grep -lZ with xargs -0 so a matching path with spaces does not get split. This combination is the safe default for codemods in a pipeline.
Common errors in CI
Without -Z/-0, a matching file named "old config.js" splits into "old" and "config.js" and sed reports "can't read old: No such file or directory". Without -r, an empty match list makes sed wait on stdin or error. grep exits 1 when nothing matches, so guard the pipeline if a no-match run should not fail the step.