bigla
bigla

Reputation: 98

How to move a block of text to the end of a range (with sed)?

Since I searched for this so many times and could not find a simple (failsafe) solution.

Problem

Consider the following snippet. Of which I want to move the block BLOCK_ONE to the end of the Range RANGE_END.

if(condition)
    string(RANGE_BEGIN          # RANGE_BEGIN
        "$<$<BLOCK_ONE>:"       # BLOCK_ONE BEGIN
            "Boost::system;"
            "Boost::filesystem;"
        ">"                     # BLOCK_ONE END
        "$<$<BLOCK_TWO>:"
            "otherlib;"
            "somelib;"
        ">" 
        "$<$<BLOCK_THREE>:"
            "comctl32;"
        ">"
    )                           # RANGE_END
elseif(othercondition)
    string(RANGE_BEGIN          # RANGE_BEGIN
        "$<$<BLOCK_ONE>:"       # BLOCK_ONE BEGIN
            "pthread;"
            "Zlib::minizip;"
        ">"                     # BLOCK_ONE END
        "$<$<BLOCK_FOUR>:"
            "somelib;"
        ">"
    )                           # RANGE_END
endif()

Goal

if(condition)
    string(RANGE_BEGIN          # RANGE_BEGIN
        "$<$<BLOCK_TWO>:"
            "otherlib;"
            "somelib;"
        ">" 
        "$<$<BLOCK_THREE>:"
            "comctl32;"
        ">"
        "$<$<BLOCK_ONE>:"       # BLOCK_ONE BEGIN
            "Boost::system;"
            "Boost::filesystem;"
        ">"                     # BLOCK_ONE END
    )                           # RANGE_END
elseif(othercondition)
    string(RANGE_BEGIN          # RANGE_BEGIN
        "$<$<BLOCK_FOUR>:"
            "somelib;"
        ">"
        "$<$<BLOCK_ONE>:"       # BLOCK_ONE BEGIN
            "pthread;"
            "Zlib::minizip;"
        ">"                     # BLOCK_ONE END
    )                           # RANGE_END
endif()

Upvotes: 1

Views: 73

Answers (2)

potong
potong

Reputation: 58483

This might work for you (GNU sed):

sed -n '/BLOCK_ONE/{h;:a;n;H;/">"/!ba;:b;n;/)/!{p;bb};H;x};p' file

Focus on a line containing BLOCK_ONE, then gather up further lines in the hold space until a line containing ">". Print further lines until a line containing ), then append this line to the hold space, swap to the hold space and print the those lines. All other lines are printed as normal.

Upvotes: 1

bigla
bigla

Reputation: 98

Warning: This won't work correctly if BLOCK_ONE is not found. (It will move the parenthesis to the next parenthesis in a range.)

Here comes the solution I used:


sed '/RANGE_BEGIN/,/)/{     # Do the following within given range (/BEGIN/,/END/)
        /BLOCK_ONE/,/">"/{  # Do the following within given range (/BEGIN/,/END/)
            /BLOCK_ONE/h    # BLOCK_ONE containing line: overwrite hold space with it
            /BLOCK_ONE/!H   # BLOCK_ONE non-containing line: append it to hold space
            d               # Delete what you read (past tense)
        }
        /)/{                # End of RANGE
            x               # eXchange pattern with hold space 
                            # (replace the line with everything you collected before, 
                            # keeping the replaced line in hold space)
            G               # Add newline and Get the line we saved with x printed
        }
}' InputFile.cmake

For people preferring one line, here it is:

sed '/RANGE_BEGIN/,/)/{/BLOCK_ONE/,/">"/{/BLOCK_ONE/h;/BLOCK_ONE/!H;d};/)/{x;G}}' InFile

Upvotes: 1

Related Questions