How can I make use of the sed H, h, x, g, G etc. commands to swap two lines?
For example in the file
START
this is a dog
this is a cat
this is something else
END
say I want to swap “this is a dog” with “this is something else”.
This is what I have so far:
/this is a dog/{
h # put to hold space
}
/this is something else/{
# now i am stuck on what to do.
}
If you know a pattern on each of the two lines you want to swap, but not the full contents of the lines, you can do something like this:
The substitution pattern keeps “dog” at the end of the accumulated lines. It keeps swapping the last two lines that we’re keeping in hold space so that “dog” “bubbles” to the bottom.
For example, let’s put another line after the “cat” line so the process is a little clearer. We’ll ignore the lines before “dog” and after “something”. And I’ll continue to refer to the lines using my nicknames
“Dog” is read, then “cat” is fetched. Some appending and swapping is done. Now pattern space looks like this (
\Nrepresents a newline, I’m using an upper case “N” so it stands out, the^is the beginning of the pattern space and$is the end):The substitution command looks for any number of characters that are not newlines (and captures them) followed by a newline followed by any number of characters that are not newlines (and captures them) that are at the end of the line ($) and replaces all that with the two captured strings in the reverse order separated by a newline. Now pattern space looks like this:
Now we swap and read a new line. It’s not “something” so we do some appending and swapping and now we have:
We do the substitution again and get:
Why didn’t we get “bear/dog/cat” instead? Because the regex pattern consisting of two lines (which each, as usual, consist of non-newlines followed by a newline) is anchored at the end of the line using the
$so we’re ignoring anything that comes before it. Note that the last newline is implied and doesn’t actually exist in pattern or hold space. That’s why I’m not showing it here.Now we read “something” and print it. We swap. Hey! there’s that stuff that we’ve been “bubbling”. Branch and print. Since “dog” is at the bottom of the lines (that had been accumulated in hold space) and we printed “something” right before that bunch, the effect is that we swapped the two lines.
This script will work regardless of how many lines appear before, between or after the two lines to be swapped. In fact, if there are multiple pairs of matching lines, the members of each pair will be swapped throughout the file.
As you can see, I’m keying on just one word in the lines of interest, but any suitable regular expression would do.