Follow Techotopia on Twitter

On-line Guides
All Guides
eBook Store
iOS / Android
Linux for Beginners
Office Productivity
Linux Installation
Linux Security
Linux Utilities
Linux Virtualization
Linux Kernel
System/Network Admin
Scripting Languages
Development Tools
Web Development
GUI Toolkits/Desktop
Mail Systems
Eclipse Documentation

How To Guides
General System Admin
Linux Security
Linux Filesystems
Web Servers
Graphics & Desktop
PC Hardware
Problem Solutions
Privacy Policy




The sed FAQ
Prev Home Next

4.41. How do I make substitutions in every file in a directory, or in a complete directory tree?

4.41.1. - ssed and Perl solution

The best solution for multiple files in a single directory is to use ssed or gsed v4.0 or higher:

     sed -i.BAK 's|foo|bar|g' files       # -i does in-place replacement

If you don't have ssed, there is a similar solution in Perl. (Yes, we know this is a FAQ file for sed, not perl, but perl is more common than ssed for many users.)

     perl -pi.bak -e 's|foo|bar|g' files                # or
     perl -pi.bak -e 's|foo|bar|g' `find /pathname -name "filespec"`

For each file in the filelist, sed (or Perl) renames the source file to "filename.bak"; the modified file gets the original filename. Remove '.bak' if you don't need backup copies. (Note the use of "s|||" instead of "s///" here, and in the scripts below. The vertical bars in the 's' command let you replace '/some/path' with '/another/path', accommodating slashes in the LHS and RHS.)

To recurse directories in Unix or GNU/Linux:

     # We use xargs to prevent passing too many filenames to sed, but
     # this command will fail if filenames contain spaces or newlines.
     find /my/path -name '*.ht' -print | xargs sed -i.BAK 's|foo|bar|g'

To recurse directories under Windows 2000 (CMD.EXE or COMMAND.COM):

     # This syntax isn't supported under Windows 9x COMMAND.COM
     for /R c:\my\path %f in (*.htm) do sed -i.BAK "s|foo|bar|g" %f
4.41.2. - Unix solution

For all files in a single directory, assuming they end with *.txt and you have no files named "[anything].txt.bak" already, use a shell script:

     #! /bin/sh
     # Source files are saved as "filename.txt.bak" in case of error
     # The '&&' after cp is an additional safety feature
     for file in *.txt
        cp $file $file.bak &&
        sed 's|foo|bar|g' $file.bak >$file

To do an entire directory tree, use the Unix utility find, like so (thanks to Jim Dennis <[email protected]> for this script):

     #! /bin/sh
     # filename: replaceall
     # Backup files are NOT saved in this script.
     find . -type f -name '*.txt' -print | while read i
        sed 's|foo|bar|g' $i > $i.tmp && mv $i.tmp $i

This previous shell script recurses through the directory tree, finding only files in the directory (not symbolic links, which will be encountered by the shell command "for file in *.txt", above). To preserve file permissions and make backup copies, use the 2-line cp routine of the earlier script instead of "sed ... && mv ...". By replacing the sed command 's|foo|bar|g' with something like

     sed "s|$1|$2|g" ${i}.bak > $i

using double quotes instead of single quotes, the user can also employ positional parameters on the shell script command tail, thus reusing the script from time to time. For example,

       replaceall East West

would modify all your *.txt files in the current directory.

4.41.3. - DOS solution:

MS-DOS users should use two batch files like this:

      @echo off
      :: MS-DOS filename: REPLACE.BAT
      :: Create a destination directory to put the new files.
      :: Note: The next command will fail under Novel Netware
      :: below version 4.10 unless "SHOW DOTS=ON" is active.
      if not exist .\NEWFILES\NUL mkdir NEWFILES
      for %%f in (*.txt) do CALL REPL_2.BAT %%f
      echo Done!!
      :: ---End of first batch file---
      @echo off
      :: MS-DOS filename: REPL_2.BAT
      sed "s/foo/bar/g" %1 > NEWFILES\%1
      :: ---End of the second batch file---

When finished, the current directory contains all the original files, and the newly-created NEWFILES subdirectory contains the modified *.TXT files. Do not attempt a command like

       for %%f in (*.txt) do sed "s/foo/bar/g" %%f >NEWFILES\%%f

under any version of MS-DOS because the output filename will be created as a literal '%f' in the NEWFILES directory before the %%f is expanded to become each filename in (*.txt). This occurs because MS-DOS creates output filenames via redirection commands before it expands "" variables.

To recurse through an entire directory tree in MS-DOS requires a batch file more complex than we have room to describe. Examine the file SWEEP.BAT in Timo Salmi's great archive of batch tricks, located at <> (this file is regularly updated). Another alternative is to get an external program designed for directory recursion. Here are some recommended programs for directory recursion. The first one, FORALL, runs under either OS/2 or DOS. Unfortunately, none of these supports Win9x long filenames.
The sed FAQ
Prev Home Next

   Reprinted courtesy of Eric Pement. Also available at Design by Interspire