Remove paragraph from file

6,201

Solution 1

Actually, sed can also take ranges. This command will delete all lines between Match user foo and the first empty line (inclusive):

$ sed '/Match user foo/,/^\s*$/{d}' file


Match user bar
        ChrootDirectory /NAS/bar.co.uk/
        ForceCommand internal-sftp
        AllowTcpForwarding no
        GatewayPorts no
        X11Forwarding no



Match user baz
        ChrootDirectory /NAS/baz.com/
        ForceCommand internal-sftp
        AllowTcpForwarding no
        GatewayPorts no
        X11Forwarding no

Personally, however, I would do this using perl's paragraph mode (-00) that has the benefit of removing the leading blank lines:

$ perl -00ne 'print unless /Match user foo/' file
Match user bar
        ChrootDirectory /NAS/bar.co.uk/
        ForceCommand internal-sftp
        AllowTcpForwarding no
        GatewayPorts no
        X11Forwarding no

Match user baz
        ChrootDirectory /NAS/baz.com/
        ForceCommand internal-sftp
        AllowTcpForwarding no
        GatewayPorts no
        X11Forwarding no

In both cases, you can use -i to edit the file in place (these will create a backup of the original called file.bak):

sed -i.bak '/Match user foo/,/^\s*$/{d}' file

or

perl -i.bak -00ne 'print unless /Match user foo/' file 

Solution 2

Slightly more complicated than terdon’s sed answer:

awk '/foo/ {suppress=1} /^\s*$/ {suppress=0} !suppress' file.php

produces almost exactly the same result as terdon’s answer:

...



Match user bar
        ChrootDirectory /NAS/bar.co.uk/
        ForceCommand internal-sftp
        AllowTcpForwarding no
        GatewayPorts no
        X11Forwarding no



Match user baz
        ChrootDirectory /NAS/baz.com/
        ForceCommand internal-sftp
        AllowTcpForwarding no
        GatewayPorts no
        X11Forwarding no

i.e., it deletes (suppresses) every line starting with the one that matches foo up to the first subsequent line that contains only whitespace.  Lines 8, 9, and 10, which are blank in the file.php input file (between user foo and user bar) come out in the output.  By contrast, terdon’s answer deletes every line starting with the one that matches foo up through the first subsequent line that contains only whitespace; so line 8 is deleted, but 9 and 10 come through.

These are not exactly what the user asked for.

awk '/foo/ {suppress=1}
     /^\s*$/ && suppress==1 {suppress=2}
     /[^\s]/ && suppress==2 {suppress=0}
     !suppress' file.php

is.  (This is broken into multiple lines for readability; it could be entered all on one line.)  When it sees foo, it goes into suppress mode #1 (suppress=1).  When it sees a blank line while in suppress mode #1, it switches into suppress mode #2.  When it sees a non-blank line while in suppress mode #2, it switches into mode 0.  Finally, it does the obvious — print lines that are not suppressed.

Share:
6,201

Related videos on Youtube

maxisme
Author by

maxisme

Updated on September 18, 2022

Comments

  • maxisme
    maxisme over 1 year

    I have a file (file.php) like this:

    ...
    Match user foo
            ChrootDirectory /NAS/foo.info/
            ForceCommand internal-sftp
            AllowTcpForwarding no
            GatewayPorts no
            X11Forwarding no
    
    
    
    Match user bar
            ChrootDirectory /NAS/bar.co.uk/
            ForceCommand internal-sftp
            AllowTcpForwarding no
            GatewayPorts no
            X11Forwarding no
    
    
    
    Match user baz
            ChrootDirectory /NAS/baz.com/
            ForceCommand internal-sftp
            AllowTcpForwarding no
            GatewayPorts no
            X11Forwarding no
    

    I am trying to write a bash script to delete one of the paragraphs.


    So say I wanted delete the user foo from the file.php. After running the script, it would then look like this:

    ...
    Match user bar
            ChrootDirectory /NAS/bar.co.uk/
            ForceCommand internal-sftp
            AllowTcpForwarding no
            GatewayPorts no
            X11Forwarding no
    
    
    
    Match user baz
            ChrootDirectory /NAS/baz.com/
            ForceCommand internal-sftp
            AllowTcpForwarding no
            GatewayPorts no
            X11Forwarding no
    

    How could I go about doing this. I have thought about using sed but that only seems to be appropriate for one liners?

    sed -i 's/foo//g' file.php
    

    And I couldn't do it for each individual line as most of the lines withing the paragraph are not unique! Any ideas?

    • Admin
      Admin about 9 years
      Sorry, I rejected your edit without realizing you were the OP. In any case, I don't like giving the -i switch without explicitly stating that it will change the original file. I have now included it.
    • Admin
      Admin about 9 years
      Haha fair enough! Thank you for answering!
  • Michaël Le Barbier
    Michaël Le Barbier almost 7 years
    Nice little finite state automaton here.