sed Notes

Collection of great links to sed tutorials, docs, types, etc.

How to replace a string in thousands of files...

If all in the same subdirectory, ...

  $ sed -i 's/text/replacement/g' file1 file2 ...  filen

Otherwise, ...

  # grep -l <string> <filenames> | xargs sed -i 's/<string>/<replacement>/'

(Yeah, that doesn't work despite claims.) Here's how I do it. My example is replacing "java-junit-test-files" everywhere with TestUtilities.JAVA_UNIT_TEST_FILES:

  # find . -name '*.java' -exec sed -i 's/\"java-junit-test-files\"/TestUtilities.JAVA_UNIT_TEST_FILES/' {} \;

How this works

Option -l (that’s not the number, but the lower-case letter) causes filenames to be output that contain <string>. xargs takes these and feeds them one at a time to sed which replaces the first occurrance of <string> in <replacement>. Option -i tells sed to work within the file on which it’s called, renaming the temporary file sed creates back to the original filename when finished (no temporary file is left over after the deed). For example, let’s replace “[email protected]” in all the text files in the current directory with “[email protected]”:

  # grep -l [email protected] <filenames> | xargs sed -i 's/[email protected]/[email protected]/'


How to sed from bash...

Sometimes, you can play with a command and accomplish a lot, get it just perfect, but, inexplicably, it won't work in the larger script. The single quotes impede the expansion of the shell variables ($HTTP_PORT, etc.). I'm used to single-quoting the match/replace string. If sed doesn't work in your script, try removing the quotes to see if that doesn't fix it.

Observe the two scripts below, one of which works and the other does not. It's the second set that finally worked for me though I had to back-tick the whole thing to get the redirection to work.

These sed statements here worked in isolation (command line trials), but not inserted in the context of a larger script:

	#!/bin/sh
	.
	.
	.
	DEFAULT_HTTP_PORT=8080
	        HTTP_PORT=48080
	 DEFAULT_AJP_PORT=8009
	         AJP_PORT=48009
	.
	.
	.
	rm  -f server.xml.old
	sed 's/$DEFAULT_HTTP_PORT/$HTTP_PORT/g' server.xml > server.xml.1
	sed 's/$DEFAULT_AJP_PORT/$AJP_PORT/g' server.xml.1 > server.xml.2
	mv  server.xml   server.xml.old
	cp  server.xml.2 server.xml
	rm  server.xml.1 server.xml.2
	.
	.
	.

This set worked. All I had to do was remove the single quotes.

	#!/bin/sh
	.
	.
	.
	DEFAULT_HTTP_PORT=8080
	        HTTP_PORT=48080
	 DEFAULT_AJP_PORT=8009
	         AJP_PORT=48009
	.
	.
	.
	rm  -f server.xml.old
	`sed s/$DEFAULT_HTTP_PORT/$HTTP_PORT/g server.xml > server.xml.1`
	`sed s/$DEFAULT_AJP_PORT/$AJP_PORT/g server.xml.1 > server.xml.2`
	mv  server.xml   server.xml.old
	cp  server.xml.2 server.xml
	rm  server.xml.1 server.xml.2
	.
	.
	.

How to embed paths and variables inside sed in a shell script

In this command, there is a file whose contents come out of variable DATA, input to sed and, in those contents, the line

    pidfile /usr/local/var/run/redis.pid

is to be replaced by

    pidfile $PIDFILE

that is, the usual Redis file is to be replaced by the new path specified in variable PIDFILE. (The file being modified is a Redis configuration file.)

1. Embed a path: the path contains slashes, which are the typical delimiter in a sed command. Simply replace sed's delimiter with another character, here @. Maybe a better character would be the vertical bar.

2. Often the single quote is used to bracket a sed search/replace string. In order to get proper expansion of the variable, PIDFILE, double quotes must be used.

3. The <<< operator directs input from variable DATA.

Here's the script line:

OUTPUT=$(sed "s@pidfile /usr/local/var/run/redis.pid@pidfile ${PIDFILE}@" <<< "${DATA}")