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

Popular posts from this blog

asp.net - repeatedly call AddImageUrl(url) to assemble pdf document -

java - Android recognize cell phone with keyboard or not? -

iphone - How would you achieve a LED Scrolling effect? -