Chapter 6. Sed Hold and Pattern Space Commands
Sed has two types of internal storage space:
- Pattern space: You already know about pattern space, which is used as part of the typical sed execution flow. Pattern space is the internal sed buffer where sed places, and modifies, the line it reads from the input file.
- Hold space: This is an additional buffer available where sed can hold temporary data. Sed allows you to move data back and forth between pattern space and hold space, but you cannot execute the typical sed commands on the hold space. As we already discussed, pattern space gets deleted at the end of every cycle in a typical sed execution flow. However, the content of the hold space will is retained from one cycle to the next; it is not deleted between cycles.
$ vi empnametitle.txt John Doe CEO Jason Smith IT Manager Raj Reddy Sysadmin Anand Ram Developer Jane Miller Sales ManagerAs you can see, for each employee this file contains name and title on two consecutive lines.
41. Swap Pattern Space with Hold Space (x command)
The sed Exchange (x) command swaps pattern space with hold space. This command in itself is not that helpful, unless it is combined with other sed commands; however, in conjunction with other commands, it is quite powerful. Suppose that pattern space contains "line 1" and hold space contains "line 2". After the x command is executed, pattern space will have "line 2", and hold space will have "line 1". The following example prints the names of the managers. It looks for the keyword 'Manager' and prints the previous line. Print manager names from empnametitle.txt:$ sed -n -e 'x;n' -e '/Manager/{x;p}' empnametitle.txt Jason Smith Jane MillerIn the above example:
- {x;n} - x swaps pattern space to the hold space; n reads the next line into the pattern space. So, this command saves the current line in hold space and reads the next line into pattern space. For the example file, it is saving employee name to hold space and fetching employee title into pattern space.
- Manager/{x;p} - If the content of the pattern space contains the keyword 'Manager', this command swaps pattern space with hold space and then prints pattern space. This means that if the employee title contains 'Manager' the employee name will be printed.
$ vi x.sed #!/bin/sed -nf x;n /Manager/{x;p} $ chmod u+x empnametitle.txt $ ./x.sed empnametitle.txt Jason Smith Jane Miller
42. Copy Pattern Space to Hold Space (h command)
The hold command (h) copies pattern space to hold space. Unlike the x command, the h command does not change the content of pattern space. The previous content of the hold space is overwritten with the content from the pattern space. Suppose pattern space contains "line 1" and hold space contains "line 2"; after the h command is executed, pattern space is not changed and will still have "line 1", but hold space will also have "line 1". Print the names of the managers:$ sed -n -e '/Manager/!h' -e '/Manager/{x;p}' empnametitle.txt Jason Smith Jane MillerThe above command should be executed in a single line as shown below.
sed -n -e '/Manager/!h' -e '/Manager/{x;p}' empnametitle.txtIn the above example: /Manager/!h - If the content of the pattern space doesn't contain Manager (the ! after the pattern means "not equal to" the pattern), copy the content of the pattern space to the hold space. (In this case, this might be employee name (or) a title that is not "Manager".) Note that, unlike the previous example, this one does not use the 'n' command to get the next line; instead, the next line is fetched via normal execution flow. /Manager/{x;p} - If the content of the pattern space contains the keyword 'Manager', this command swaps pattern space with hold space and prints. This is identical to the command we used for printing in the example for the x command. You can also save this in a sed script file and execute it as shown below.
$ vi h.sed #!/bin/sed -nf /Manager/!h /Manager/{x;p} $ chmod u+x empnametitle.txt $ ./h.sed empnametitle.txt Jason Smith Jane Miller
43. Append Pattern Space to Hold Space (H command)
Capital H is the command to append pattern space to hold space with a new line. The previous content of hold space is not overwritten; instead the content of pattern space is appended to the existing content of hold space by adding a new line at the end. Suppose pattern space contains "line 1" and hold space contains "line 2"; after the H command is executed, pattern space is not changed and will still have "line 1", but hold space will have "line 2\nline 1". Print the name and title (in separate lines) of the managers:$ sed -n -e '/Manager/!h' -e '/Manager/{H;x;p}' empnametitle.txt Jason Smith IT Manager Jane Miller Sales ManagerThe above command should be executed in a single line as shown below.
sed -n -e '/Manager/!h' -e '/Manager/{H;x;p}' empnametitle.txtIn the above example:
- /Manager/!h - If the content of the pattern space doesn't contain Manager (the ! after the pattern means "not equal to" the pattern), copy the content of the pattern space to the hold space. (In this case, this might employee name (or) a title that is not "Manager".) This is the same command we used in the h command example.
- /Manager/{H;x;p} - If the content of the pattern space contains the keyword 'Manager', the H command appends pattern space (which is Manager) to hold space with a new line. So, the hold space at this stage will have "Employee Name\nTitle" (which contains the keyword manager). The x command swaps hold space back into pattern space, and p prints the pattern space.
$ vi H-upper.sed #!/bin/sed -nf /Manager/!h /Manager/{H;x;p} $ chmod u+x H-upper.sed $ ./H-upper.sed empnametitle.txt Jason Smith IT Manager Jane Miller Sales ManagerThe above example can be slightly modified, if you want the employee name and title to be printed on the same line with colon : as a delimiter:
$ sed -n -e '/Manager/!h' -e '/Manager/{H;x;s/\n/:/;p}' empnametitle.txt Jason Smith:IT Manager Jane Miller:Sales ManagerThe above command should be executed in a single line as shown below.
sed -n -e '/Manager/!h' -e '/Manager/{H;x;s/\n/:/;p}' empnametitle.txtIn the second example everything is same as the previous example except for the substitute command added to the 2nd -e option. The H, x, and p commands do the same thing as before; the s command replaces \n with : after swapping but before printing. Therefore the name and title are printed on one line, separated by a colon. You can also save this in a sed script file and execute it as shown below.
$ vi H1-upper.sed #!/bin/sed -nf /Manager/!h /Manager/{H;x;s/\n/:/;p} $ chmod u+x H1-upper.sed $ ./H1-upper.sed empnametitle.txt Jason Smith:IT Manager Jane Miller:Sales Manager
44. Copy Hold Space to Pattern Space (g command)
The sed get (g) command copies the content of hold space to pattern space. Think of it this way: h command "holds" it in the hold space, g command "gets" it from the hold space. Suppose pattern space contains "line 1" and hold space contains "line 2"; after the g command is executed, pattern space is changed and now contains "line 2", while hold space is not changed and still contains "line 2". Print the names of the managers:$ sed -n -e '/Manager/!h' -e '/Manager/{g;p}' empnametitle.txt Jason Smith Jane MillerThe above command should be executed in a single line as shown below.
sed -n -e '/Manager/!h' -e '/Manager/{g;p}' empnametitle.txtIn the above example: /Manager/!h – we've been using this one for the last few examples. If the content of the pattern space doesn't contain Manager, copy the content of pattern space to hold space. /Manager/{g;p} – g gets the line from hold space and puts it in pattern space, then prints it. You can also save this in a sed script file and execute it as shown below.
$ vi g.sed #!/bin/sed -nf /Manager/!h /Manager/{g;p} $ chmod u+x g.sed $ ./g.sed empnametitle.txt Jason Smith Jane Miller
45. Append Hold Space to Pattern Space (G command)
Upper case G appends the content of hold space to pattern space with a new line. The previous content in the pattern space is not overwritten; instead the content from hold space is appended to the existing content in pattern space by adding a new line at the end. G and g are related in the same way as H and h; the lower case version replaces the content while the upper case one appends to it. Suppose pattern space contains "line 1" and hold space contains "line 2"; after the G command is executed, pattern space is changed to contain "line 1\nline 2" while hold space is not changed and still contains "line 2". Prints the employee name and title of the managers separated by colon.$ sed -n -e '/Manager/!h' -e '/Manager/{x;G;s/\n/:/;p}' empnametitle.txt Jason Smith:IT Manager Jane Miller:Sales ManagerThe above command should be executed in a single line as shown below.
sed -n -e '/Manager/!h' -e '/Manager/{x;G;s/\n/:/;p}' empnametitle.txtIn the above example:
- /Manager/!h – As in previous examples, if the content of pattern space doesn't contain Manager, copy pattern space to hold space.
- /Manager/{x;G;s/\n/:/;p} - If the content of the pattern space contains Manager, do the following:
- x - Swap the content of pattern space with hold space. So, the employee name stored in hold space will now be in pattern space, while the title will be in hold space.
- G - Appends the content of hold space (title) to pattern space (employee name). So, the pattern space at this stage will have "Employee Name\nTitle"
- s/\n/:/ This replaces the \n that separates the "Employee Name\nTitle" with a colon :
- p prints the result (i.e. the content of pattern space).
- Note that if we left out the x command, i.e. if we used /Manager/{G;s/\n/:/;p}, we would print the title:name instead of name:title for each manager.
$ vi G-upper.sed #!/bin/sed -nf /Manager/!h /Manager/{x;G;s/\n/:/;p} $ chmod u+x G-upper.sed $ ./G-upper.sed empnametitle.txt Jason Smith:IT Manager Jane Miller:Sales Manager