Linux: how to replace all instances of a string with another in all files of a single type
You have the sed
and the find
back to front. With GNU sed
and the -i
option, you could use:
find . -name '*.txt' -type f -exec sed -i s/123/321/g {} +
The find
finds files with extension .txt
and runs the sed -i
command on groups of them (that's the +
at the end; it's standard in POSIX 2008, but not all versions of find
necessarily support it). In this example substitution, there's no danger of misinterpretation of the s/123/321/g
command so I've not enclosed it in quotes. However, for simplicity and general safety, it is probably better to enclose the sed
script in single quotes whenever possible.
You could also use xargs
(and again using GNU extensions -print0
to find
and -0
and -r
to xargs
):
find . -name '*.txt' -type f -print0 | xargs -0 -r sed -i 's/123/321/g'
The -r
means 'do not run if there are no arguments' (so the find
doesn't find anything). The -print0
and -0
work in tandem, generating file names ending with the C null byte '\0'
instead of a newline, and avoiding misinterpretation of file names containing newlines, blanks and so on.
Note that before running the script on the real data, you can and should test it. Make a dummy directory (I usually call it junk
), copy some sample files into the junk directory, change directory into the junk directory, and test your script on those files. Since they're copies, there's no harm done if something goes wrong. And you can simply remove everything in the directory afterwards: rm -fr junk
should never cause you anguish.
Jean-Luc Nacif Coelho
Updated on June 14, 2022Comments
-
Jean-Luc Nacif Coelho almost 2 years
I want to replace for example all instances of "123" with "321" contained within all .txt files in a folder (recursively). I thought of doing this
sed -i 's/123/321/g' | find . -name \*.txt
but before possibly screwing all my files I would like to ask if it will work.
-
Jean-Luc Nacif Coelho over 11 yearsThanks. That worked just fine with a little tweak: you forgot the quotes find . -name '*.txt' -type f -exec sed -i 's/123/321/g {}' +
-
Jonathan Leffler over 11 yearsInteresting; were I to be asked, I'd have said that the quotes you show would break it, rather than fix it. But who am I to argue with the empirical evidence...