Like other programming languages, SED too provides a looping and branching facility to control the flow of execution. In this chapter, we are going to explore more about how to use loops and branches in SED.
A loop in SED works similar to a goto statement. SED can jump to the line marked by the label and continue executing the remaining commands. In SED, we can define a label as follows:
:label :start :end :up
In the above example, a name after colon(:) implies the label name.
To jump to a specific label, we can use the b command followed by the label name. If the label name is omitted, then the SED jumps to the end of the SED file.
Let us write a simple SED script to understand the loops and branches. In our books.txt file, there are several entries of book titles and their authors. The following example combines a book title and its author name in one line separated by a comma. Then it searches for the pattern “Paulo”. If the pattern matches, it prints a hyphen(-) in front of the line, otherwise it jumps to the Print label which prints the line.
[jerry]$ sed -n ' h;n;H;x s/\n/, / /Paulo/!b Print s/^/- / :Print p' books.txt
On executing the above code, you get the following result:
A Storm of Swords, George R. R. Martin The Two Towers, J. R. R. Tolkien - The Alchemist, Paulo Coelho The Fellowship of the Ring, J. R. R. Tolkien - The Pilgrimage, Paulo Coelho
A Game of Thrones, George R. R. Martin
At first glance, the above script may look cryptic. Let us demystify this.
- The first two commands are self-explanatory h;n;H;x and s/\n/, / combine the book title and its author separated by a comma(,).
- The third command jumps to the label Print only when the pattern does not match, otherwise substitution is performed by the fourth command.
- :Print is just a label name and as you already know, p is the print command.
To improve readability, each SED command is placed on a separate line. However, one can choose to place all the commands in one line as follows:
[jerry]$ sed -n 'h;n;H;x;s/\n/, /;/Paulo/!b Print; s/^/- /; :Print;p' books.txt
On executing the above code, you get the following result:
A Storm of Swords, George R. R. Martin The Two Towers, J. R. R. Tolkien - The Alchemist, Paulo Coelho The Fellowship of the Ring, J. R. R. Tolkien - The Pilgrimage, Paulo Coelho A Game of Thrones, George R. R. Martin