web-dev-qa-db-ja.com

ファイルから段落を削除

次のようなファイル(file.php)があります。

...
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

段落の1つを削除するbashスクリプトを作成しようとしています。


つまり、ユーザーfoofile.phpから削除したいとします。スクリプトを実行すると、次のようになります。

...
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

どうすればこれを実行できますか? sedを使用することを考えましたが、それは1つのライナーにのみ適切であると思われますか?

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

そして、段落を含むほとんどの行は一意ではないので、個々の行ごとにそれを行うことはできませんでした!何か案は?

6
maxisme

実際には、sedも範囲を取ることができます。このコマンドは、Match user fooと最初の空の行(両端を含む)の間のすべての行を削除します。

$ 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

ただし、個人的には、Perlの段落モード(-00)を使用してこれを行います。これには、先​​頭の空白行を削除するという利点があります。

$ 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

どちらの場合も、-iを使用してファイルを編集できます(これにより、元のfile.bakのバックアップが作成されます)。

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

または

Perl -i.bak -00ne 'print unless /Match user foo/' file 
6
terdon

Terdonのsed回答よりも少し複雑です:

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

terdonの答えとほぼ同じ結果が得られます。

...



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

つまり、foo up toに一致する行で始まるすべての行を削除(抑制)します。これは、空白のみを含む最初の後続行です。 file.php入力ファイル(user foouser barの間)で空白の行8、9、および10が出力に出力されます。対照的に、terdonの回答は、foo up throughに一致する行で始まるすべての行を削除します。空白のみを含む最初の後続行。したがって、8行目は削除されますが、9と10は通過します。

これらは、ユーザーが要求したものとは正確には異なります。

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

です。 (これは読みやすくするために複数の行に分割されています。1行ですべて入力できます。)fooが見つかると、抑制モード#1(suppress=1)になります。抑制モード#1で空白行が表示されると、抑制モード#2に切り替わります。抑制モード#2で空白以外の行が表示されると、モード0に切り替わります。最後に、suppressedされていない行を出力します。

3
Scott