Linux: how to replace all instances of a string with another in all files of a single type

13,053

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.

Share:
13,053
Jean-Luc Nacif Coelho
Author by

Jean-Luc Nacif Coelho

Updated on June 14, 2022

Comments

  • Jean-Luc Nacif Coelho
    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
    Jean-Luc Nacif Coelho over 11 years
    Thanks. 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
    Jonathan Leffler over 11 years
    Interesting; 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...