Skip to content
Latchkey

sed Across Many Files with find in CI

Combining sed -i with find or a glob rewrites the same pattern across a whole tree of files in one step.

Repo-wide renames and config sweeps are a job for sed plus find. The edit is the easy part; the traps are quoting, the -i flavor split, and accidentally matching too much.

What it does

sed -i edits each file it is given in place. A shell glob or find feeds it the file list, so one command applies the same substitution everywhere. find -exec or xargs scales to large trees and handles awkward filenames.

Common usage

Terminal
# glob: every yaml file in the directory (GNU sed)
sed -i 's/old/new/g' *.yml

# find -exec for a whole tree, batched
find . -name '*.conf' -exec sed -i 's/old/new/g' {} +

# xargs with NUL-safe filenames
find . -name '*.ini' -print0 | xargs -0 sed -i 's/old/new/g'

Options

FormWhat it does
sed -i '...' *.extEdit every file matching the glob
find ... -exec sed -i {} +Batch many files into few sed calls
find -print0 | xargs -0Handle names with spaces or newlines
-i.bakKeep a backup of each edited file (GNU)
grep -l firstLimit to files that actually contain the pattern

In CI

On ubuntu-latest, find ... -exec sed -i 's/.../.../ ' {} + is the standard sweep. On macos-latest the same line needs sed -i '' with the empty backup argument, so guard cross-platform sweeps by branching on the OS or installing gnu-sed. Running sed only on files that match (via grep -lZ) avoids rewriting and dirtying files that did not change.

Common errors in CI

On macOS, find -exec sed -i 's/a/b/' {} + fails with sed: 1: "...": invalid command code because BSD -i needs its own argument; insert '' after -i. An empty glob with nullglob off passes the literal *.yml to sed, giving sed: can't read *.yml: No such file or directory. Always scope the pattern so a broad match does not edit unintended files.

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →