1. Introduction
The standard sed tool can parse, filter, and output file contents on demand. However, certain functions are only available in some versions.
In this tutorial, we explore ways to print to standard output when editing in place with sed. To that end, we use the example of deleting but also printing the first line of a file via a single sed command. First, we discuss the usual way the tool handles output. Next, we go over ways to control the output. Finally, we show how to use a single sed command to delete and print the first line of a file.
We tested the code in this tutorial on Debian 11 (Bullseye) with GNU Bash 5.1.4 and GNU sed 4.7. It should work in most POSIX-compliant environments unless otherwise specified.
2. sed Output
By default, the output of standard sed goes to stdout.
2.1. Default Output
Let’s use sed to delete the first line of /file:
$ cat /file
line1
line2
$ sed '1d' /file
line2
$ cat /file
line1
line2
In this example, /file preserves its contents after 1d deletes a line by its number. Still, we see the result of the deletion as the output of sed.
2.2. Output Back to File
To make changes permanent by storing them back in the file, we can use the GNU-extension –in-place or -i flag:
$ cat /file
line1
line2
$ sed -i '1d' /file
$ cat /file
line2
Now, sed doesn’t produce any output to stdout because it redirects the stream back to the original file after [d]eleting line 1.
So, we can get the sed changes on stdout and output them back to the file with –in-place (-i). Still, there is a third option we can leverage to split the output in different directions.
3. sed Output Control
Despite the seeming limitations imposed by the tool, sed can leverage internal commands to direct only certain output to stdout.
3.1. The sed Write Commands (w, W, s///w)
The exceptions to the everything-to-one approach of sed output are the write commands:
- w filename
- W filename (GNU-specific)
- s/**//w filename
The w command writes the current pattern space to a specified file by path:
$ cat /file
line1
line2
$ sed 'w /output' /file
$ cat /file
line1
line2
$ cat /output
line1
line2
Here, we see both lines of /file are on the screen but also end up in /output. Moreover, the only difference between w and W is that W cuts the pattern space to the first newline.
Of course, the s///w substitution command works the same way but writes out only the modified pattern spaces to the file path.
3.2. GNU Special Filenames (/dev/stdout, /dev/stderr)
The GNU version of sed offers another non-POSIX feature that can facilitate our aim: /dev/stdout. Actually, GNU sed provides two self-explanatory special filenames:
- /dev/stdout – standard output
- /dev/stderr – standard error
Both can serve as arguments to w, W, and s///w, depending on where we want to redirect to.
4. Using GNU sed to Split Output
Armed with the extensions of GNU sed, we can combine them in a single command with several functions:
- remove the first line of a file
- output the first line of the file to stdout
- output all other file lines back to the file itself
Let’s see this in action:
$ cat /file
line1
line2
$ sed --in-place -e '1 w /dev/stdout' -e '1d' /file
line1
$ cat file
line2
Notably, *we [-e]xecute two (linked) scripts within a single sed command*. The first gets line 1, and [w]rites it to /dev/stdout. The second [d]eletes the same line.
In fact, we can remove the two references to line 1 by using curly braces:
$ sed --in-place -e '1{w /dev/stdout' -e 'd}' /file
In general, this syntax can be more beneficial when deletions precede other actions.
5. Summary
In this article, we explored a sed-only way to delete the first line of a file while also printing it with a single command.
In conclusion, by using the GNU version of sed and several of its extensions, we can produce complex output redirections.