Reputation: 763
Here is my current code, my goal is to find every file in a given directory (recursively) and replace "FIND" with "REPLACEWITH" and overwrite the files.
FIND='ALEX'
REPLACEWITH='<strong>ALEX</strong>'
DIRECTORY='/some/directory/'
find $DIRECTORY -type f -name "*.html" -print0 |
LANG=C xargs -0 sed -i "s|$FIND|$REPLACEWITH|g"
The error I am getting is:
sed: 1: "/some/directory ...": command a expects \ followed by text
Upvotes: 3
Views: 2098
Reputation: 295954
As given in BashFAQ #21, you can use perl
to perform search-and-replace operations with no potential for data being treated as code:
in="$FIND" out="$REPLACEWITH" find "$DIRECTORY" -type f -name '*.html' \
-exec perl -pi -e 's/\Q$ENV{"in"}/$ENV{"out"}/g' '{}' +
If you want to include only files matching the FIND string, find
can be told to only pass files which grep
flags on to perl
:
in="$FIND" out="$REPLACEWITH" find "$DIRECTORY" -type f -name '*.html' \
-exec grep -F -q -e "$FIND" '{}' ';' \
-exec perl -pi -e 's/\Q$ENV{"in"}/$ENV{"out"}/g' '{}' +
Because grep
is being used to evaluate individual files, it's necessary to use one grep
call per file so its exit status can be evaluated on a per-file basis; thus, the use of the less efficient -exec ... {} ';'
action. For perl
, it's possible to put multiple files to process on one command, hence the use of -exec ... {} +
.
Note that fgrep
is line-oriented; if your FIND
string contains multiple lines, then files with any one of those lines will be passed to perl
for replacements.
Upvotes: 2
Reputation: 1235
You can have find
invoke sed
directly although I think all the modification times on your files will be affected (which might matter or not):
find $DIRECTORY -type f -name "*.html" -exec sed -i "s|$FIND|$REPLACEWITH|g" '{}' ';'
Upvotes: 1