views:

563

answers:

4

I need to do a regex find and replace on all the files in a folder (and its subfolders). What would be the linux shell command to do that?

For example, I want to run this over all the files and overwrite the old file with the new, replaced text.

sed 's/old text/new text/g'
A: 

Might I suggest (after backing up your files):

find /the/folder -type f -exec sed -ibak 's/old/new/g' {} ';'
paxdiablo
+3  A: 

There is no way to do it using only sed. You'll need to use at least the find utility together:

find . -type f -exec sed -i.bak "s/foo/bar/g" {} \;

This command will create a .bak file for each changed file.

Notes:

  • The -i argument for sed command is a GNU extension, so, if you are running this command with the BSD's sed you will need to redirect the output to a new file then rename it.
  • The find utility does not implement the -exec argument in old UNIX boxes, so, you will need to use a | xargs instead.
osantana
A: 

Might want to try my mass search/replace Perl script. Has some advantages over chained-utility solutions (like not having to deal with multiple levels of shell metacharacter interpretation).

chaos
+1  A: 

For portability, I don't rely on features of sed that are specific to linux or BSD. Instead I use the overwrite script from Kernighan and Pike's book on the Unix Programming Environment.

The command is then

find /the/folder -type f -exec overwrite '{}' sed 's/old/new/g' {} ';'

And the overwrite script (which I use all over the place) is

#!/bin/sh
# overwrite:  copy standard input to output after EOF
# (final version)

# set -x

case $# in
0|1)        echo 'Usage: overwrite file cmd [args]' 1>&2; exit 2
esac

file=$1; shift
new=/tmp/$$.new; old=/tmp/$$.old
trap 'rm -f $new; exit 1' 1 2 15    # clean up files

if "$@" >$new               # collect input
then
    cp $file $old   # save original file
    trap 'trap "" 1 2 15; cp $old $file     # ignore signals
          rm -f $new $old; exit 1' 1 2 15   # during restore
    cp $new $file
else
    echo "overwrite: $1 failed, $file unchanged" 1>&2
    exit 1
fi
rm -f $new $old

The idea is that it overwrites a file only if a command succeeds. Useful in find and also where you would not want to use

sed 's/old/new/g' file > file  # THIS CODE DOES NOT WORK

because the shell truncates the file before sed can read it.

Norman Ramsey