The sed
command in UNIX is one of the most useful tools available in your arsenal. sed
stands for stream editor and it can be used to perform functions on files or standard input text streams such as searching, find and replace, insertion, or deletion. In this tutorial, we will cover some of the basic commands of sed
.
Basic Usage
$ sed [options] command [input-file]
sed
will operate on a stream of text that it either reads from an input file or from standard input (STDIN). By default sed
will send its results to standard output (STDOUT). Executing both of the following commands will print the contents of the /etc/services
file to the screen:
$ sed '' /etc/services
$ cat /etc/services | sed ''
Output:
# Network services, Internet style
#
# Note that it is presently the policy of IANA to assign a single well-known
# port number for both TCP and UDP; hence, officially ports have two entries
# even if the protocol doesn't support UDP operations.
#
# Updated from http://www.iana.org/assignments/port-numbers and other
# sources like http://www.freebsd.org/cgi/cvsweb.cgi/src/etc/services .
# New ports will be added on request if they have been officially assigned
# by IANA and used in the real-world or are needed by a debian package.
# If you need a huge list of used numbers please install the nmap package.
...
...
Printing
The commands above demonstrate that without any operations sed
would print the output of the file to STDOUT. This isn’t entirely useful as we already have other commands that will print the contents of a file to STDOUT, so let’s explore the sed
’s print command 'p'
.
We’ll modify the command above to use the print command:
$ sed 'p' /etc/services
Output:
# Network services, Internet style
# Network services, Internet style
#
#
# Note that it is presently the policy of IANA to assign a single well-known
# Note that it is presently the policy of IANA to assign a single well-known
# port number for both TCP and UDP; hence, officially ports have two entries
# port number for both TCP and UDP; hence, officially ports have two entries
# even if the protocol doesn't support UDP operations.
# even if the protocol doesn't support UDP operations.
...
...
Notice how each line is printed twice? sed
will put each line of text that is to be processed into what is known as the “Pattern” space. Before processing a line sed
will place the line into the pattern space and then apply all specified commands to the pattern space. By default sed
prints the resulted text from the pattern space to STDOUT. The command above is explicitly telling sed
to print the contents of the pattern space.
sed
can be instructed to not print the pattern space by default by using the -n
flag:
$ sed -n 'p' /etc/services
Output:
# Network services, Internet style
#
# Note that it is presently the policy of IANA to assign a single well-known
# port number for both TCP and UDP; hence, officially ports have two entries
# even if the protocol doesn't support UDP operations.
...
...
Operations by Address Ranges
Using addressing allows you to target specific parts of a text stream to operate on. For instance, we can have sed
print out a specific line by providing the line number to the print command.
$ sed -n '1p' /etc/services
Output:
# Network services, Internet style
Placing the number 1
in from of the print command informed sed
to only perform the print operation on line number 1
. We can extend this and make sed
only perform a specific operation on a range of lines. For instance the following will print the first 4 lines:
$ sed -n '1,4p' /etc/services
Output:
# Network services, Internet style
#
# Note that it is presently the policy of IANA to assign a single well-known
# port number for both TCP and UDP; hence, officially ports have two entries
The above address range has instructed sed
to only perform the print operation on all lines between line 1
and line 4
. An alternative is to specify an offset from the initial line. This can be done by adding using the +
character followed by the offset amount, like so:
$ sed -n '1,+3p' /etc/services
Output:
# Network services, Internet style
#
# Note that it is presently the policy of IANA to assign a single well-known
# port number for both TCP and UDP; hence, officially ports have two entries
sed
can also be instructed to perform operations on every line for a given interval by using the ~
character. For instance, the following will perform the print operation on every 2nd line starting at line 1.
$ sed -n '1~2p' /etc/services
Output:
# Network services, Internet style
# Note that it is presently the policy of IANA to assign a single well-known
# even if the protocol doesn't support UDP operations.
# Updated from http://www.iana.org/assignments/port-numbers and other
# New ports will be added on request if they have been officially assigned
# If you need a huge list of used numbers please install the nmap package.
tcpmux 1/tcp # TCP port service multiplexer
...
...
Operations by Pattern
sed
can not only perform operations based on address ranges but it can also perform operations on based on patterns defined by a regular expression. The regular expression must be enclosed by slashes /
. For instance, we can print all line that beginning with a certain number:
$ sed -n '/443/p' /etc/services
Output:
# Updated from https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml .
http 80/tcp www # WorldWideWeb HTTP
https 443/tcp # http protocol over TLS/SSL
http-alt 8080/tcp webcache # WWW caching service
or we can use more complex regular expressions for instance to find any line that begins with a #
character:
$ sed -n '^#/p' /etc/services
# Network services, Internet style
#
# Note that it is presently the policy of IANA to assign a single well-known
# port number for both TCP and UDP; hence, officially ports have two entries
# even if the protocol doesn't support UDP operations.
#
# Updated from https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml .
#
# New ports will be added on request if they have been officially assigned
# by IANA and used in the real-world or are needed by a debian package.
...
...
Inverse Operation
The above show how we can make sed
perform operations on specific lines but what about if we wanted to perform operations on all lines but the ones matching the address specification?
To operate on all lines that do not match the pattern we need to append the !
character to the end of the address specification.
$ sed -n '/^#/!p' /etc/services
Output
tcpmux 1/tcp # TCP port service multiplexer
echo 7/tcp
echo 7/udp
discard 9/tcp sink null
discard 9/udp sink null
systat 11/tcp users
daytime 13/tcp
daytime 13/udp
netstat 15/tcp
...
...
Deletion
Above we have demonstrated the power of sed
using the print command, however, we can replace the print command with other sed
commands. For instance, we could perform text deletion instead of printing by replacing the p
command with the d
command.
Since we don’t want to be deleting lines from the /etc/services
file we’ll use the following text file:
This is a test file.
#
It'll be used to demonstrate sed's text deletion command.
#
The file is very simple but
#
it will demonstrate how we can remove a range of lines.
As mentioned we can instruct sed
to remove all lines between a given range for such as removing all lines between line 2
and 6
by running the following command:
$ sed '2,6d' testfile.txt
Output:
This is a test file.
it will demonstrate how we can remove a range of lines.
Note: In this case we don’t need -n
as sed
will print every line that is not deleted.
We can also use the regular expressions as we did with the print command to remove any line that matches the regular expression. The command below will remove all lines beginning with the #
character:
$ sed '/^#/d' testfile.txt
Output:
This is a test file.
It'll be used to demonstrate sed's text deletion command.
The file is very simple but
it will demonstrate how we can remove a range of lines.
It is important to note that the deletion command above has not made changes to the source file. The output of the edits are only being sent to STDOUT.
If we want the edits to persist then we need to redirect the output to another file:
$ sed '2,6d' testfile.txt > editted-testfile.txt
$ cat editted-testfile.txt
Output:
This is a test file.
it will demonstrate how we can remove a range of lines.
Alternatively, we can specify that sed
should perform in-place editing with the -i
option. This option will have sed
overwrite the source file with the edits. Care should be taken when using the -i
option and therefore it is recommended to test your edits without the -i
option first.
sed -i '2,6d' testfile.txt
Thankfully though, sed
can create a backup file of the source file before editing the file. To create a backup all you need to do it add a backup extension after the -i
option:
sed -i.bak '2,6d' testfile.txt
This will create a backup of the source file called testfile.txt.bak
and then perform the edits on the original file.