stringawkseded

How to move block of text and next nth line following a pattern to end of file?


I have this ssh config that needs to be edited.

Host vps6
   HostName 123.456.789.00
   User dylan
   Port 123

Host vps4
   HostName 123.456.789.00 
   User dylan
   Port 123

# old server

Host vps3-old
   HostName 123.456.789.00
   User dylan 
   Port 123

I want to move config for vps6 to end of file and append -old to its config alias. The resulting file would be.

Host vps4
   HostName 123.456.789.00 
   User dylan
   Port 123

# old server

Host vps3-old
   HostName 123.456.789.00
   User dylan 
   Port 123

Host vps6-old
   HostName 123.456.789.00
   User dylan
   Port 123

I managed to do exactly that using this sed command → sed '/'"vps4"'/{N;N;N;N;H;$!d}; ${p;x;s/'"vps4"'/'"vps4"'-old/}', unfortunately this gives me unwanted newline at the end of file.

[tmp]$ sed '/'"vps6"'/{N;N;N;N;H;$!d}; ${p;x;s/'"vps6"'/'"vps6"'-old/}' config
Host vps4
   HostName 123.456.789.00
   User dylan
   Port 123

# old server

Host vps3-old
   HostName 123.456.789.00
   User dylan 
   Port 123

Host vps6-old
   HostName 123.456.789.00 
   User dylan
   Port 123

[tmp]$ # See above me

Moreover, I want to be able to specify the next n line to be moved (for example above will be mark Host vps4 and next 3 line to be moved to end of file). I have searched up the net and found out that the recommended tools for this kind of task is ed, but I have yet to find out the example command to do exactly what I want.


Solution

  • With your shown samples please try following awk code.

    awk '
    !NF && found{
      found=""
      next
    }
    /^Host vps6/{
      found=1
      line=$0"-old"
      next
    }
    found{
      val=(val?val ORS:"")$0
      next
    }
    !found
    END{
      print ORS line ORS val
    }
    '  Input_file
    

    NOTE: In case you want to save output into Input_file itself then run above program it will print output on terminal and once you are Happy with results of above program then you can append > temp && mv temp Input_file to above program, to do inplace save into Input_file.

    Explanation: Adding detailed explanation for above used code.

    awk '                      ##Starting awk program from here.
    !NF && found{              ##Checking if line is empty AND found is SET then do following.
      found=""                 ##Nullifying found here.
      next                     ##next will skip all further statements from here.
    }
    /^Host vps6/{              ##If line starts from Host vps6 then do following.
      found=1                  ##Setting found here.
      line=$0"-old"
      next
    }
    found{                     ##If found is set then do following.
      val=(val?val ORS:"") $0  ##Creating val which is keep adding current line into it.
      next                     ##next will skip all further statements from here.
    }
    !found                     ##If found is NOT set then print that line.
    END{                       ##Starting END block of this program from here.
      print ORS line ORS val   ##Printing ORS line ORS and val here.
    }
    '  Input_file              ##Mentioning Input_file name here.