sed - Swapping two lines -
how can make use of sed h
, h
, x
, g
, g
etc. commands swap 2 lines?
for example in file
start dog cat else end
say want swap "this dog" "this else".
this have far:
/this dog/{ h # put hold space } /this else/{ # stuck on do. }
if know pattern on each of 2 lines want swap, not full contents of lines, can this:
sed -n ' # turn off default printing /dog/{ # if line matches "dog" h # put in hold space :a # label "a" - top of loop n # fetch next line /something/{ # if matches "something" p # print x # swap hold , pattern space bb # branch out of loop label "b" } # done "something" # if we're here, line doesn't match "something" h # append pattern space hold space x # swap hold , pattern space s/\([^\n]*\)\n\([^\n]*\)$/\2\n\1/ # see below x # swap hold , pattern space ba # branch top of loop label "a" } # done "dog" :b # label "b" - outside loop # print lines don't match , outside pair p # prints had been accumulating in hold space ' inputfile
the substitution pattern keeps "dog" @ end of accumulated lines. keeps swapping last 2 lines we're keeping in hold space "dog" "bubbles" bottom.
for example, let's put line after "cat" line process little clearer. we'll ignore lines before "dog" , after "something". , i'll continue refer lines using nicknames
this dog cat there's bear here, else
"dog" read, "cat" fetched. appending , swapping done. pattern space looks (\n
represents newline, i'm using upper case "n" stands out, ^
beginning of pattern space , $
end):
^this dog\nthis cat$
the substitution command looks number of characters not newlines (and captures them) followed newline followed number of characters not newlines (and captures them) @ end of line ($) , replaces 2 captured strings in reverse order separated newline. pattern space looks this:
^this cat\nthis dog$
now swap , read new line. it's not "something" appending , swapping , have:
^this cat\nthis dog\nthere's bear here, too$
we substitution again , get:
^this cat\nthere's bear here, too\nthis dog$
why didn't "bear/dog/cat" instead? because regex pattern consisting of 2 lines (which each, usual, consist of non-newlines followed newline) anchored @ end of line using $
we're ignoring comes before it. note last newline implied , doesn't exist in pattern or hold space. that's why i'm not showing here.
now read "something" , print it. swap. hey! there's stuff we've been "bubbling". branch , print. since "dog" @ bottom of lines (that had been accumulated in hold space) , printed "something" right before bunch, effect swapped 2 lines.
this script work regardless of how many lines appear before, between or after 2 lines swapped. in fact, if there multiple pairs of matching lines, members of each pair swapped throughout file.
as can see, i'm keying on 1 word in lines of interest, suitable regular expression do.
Comments
Post a Comment