You may remember that the substitute command can write to a file:
sed -n 's/^[0-9]*[02468] /&/w even' <file
I used the "&" in the replacement part of the substitution command so that the line would not be changed. A simpler example is to use the "w" command, which has the same syntax as the "w" flag in the substitute command:
sed -n '/^[0-9]*[02468]/ w even' <file
Remember - only one space must follow the command. Anything else will be considered part of the file name. The "w" command also has the same limitation as the "w" flag: only 10 files can be opened in sed.
Reading in a file with the 'r' command
There is also a command for reading files. The command
sed '$r end' <in>out
will append the file "end" at the end of the file (address "$)." The following will insert a file after the line with the word "INCLUDE:"
sed '/INCLUDE/ r file' <in >out
You can use the curly braces to delete the line having the "INCLUDE" command on it:
#!/bin/sh
sed '/INCLUDE/ {
r file
d
}'
Click here to get file: sed_include.sh
The order of the delete command "d" and the read file command "r" is important. Change the order and it will not work. There are two subtle actions that prevent this from working. The first is the "r" command writes the file to the output stream. The file is not inserted into the pattern space, and therefore cannot be modified by any command. Therefore the delete command does not affect the data read from the file.
The other subtlty is the "d" command deletes the current data in the pattern space. Once all of the data is deleted, it does make sense that no other action will be attempted. Therefore a "d" command executed in a curly brace also aborts all further actions. As an example, the substitute command below is never executed:
#!/bin/sh
# this example is WRONG
sed -e '1 {
d
s/.*//
}'
Click here to get file: sed_bad_example.sh
The earlier example is a crude version of the C preprocessor program. The file that is included has a predetermined name. It would be nice if sed allowed a variable (e.g "\1)" instead of a fixed file name. Alas, sed doesn't have this ability. You could work around this limitation by creating sed commands on the fly, or by using shell quotes to pass variables into the sed script. Suppose you wanted to create a command that would include a file like cpp, but the filename is an argument to the script. An example of this script is:
% include 'sys/param.h' <file.c >file.c.new
A shell script to do this would be:
#!/bin/sh
# watch out for a '/' in the parameter
# use alternate search delimiter
sed -e '\_#INCLUDE <'$1'>_{
r '$1'
d
}'
Click here to get file: sed_include1.sh