sedまたはawk:パターンに続くn行を削除


105

sed(または同様のツール-awkなど)でパターンと数値範囲をどのように混在させるのですか?私がしたいことは、ファイル内の特定の行を照合し、続行する前に次のn行を削除し、それをパイプラインの一部として実行することです。

回答:


185

これでやってみます。

パターンの後の5行を削除するには(パターンのある行を含む):

sed -e '/pattern/,+5d' file.txt

パターンの後ろの5行を削除するには(パターンのある行を除く):

sed -e '/pattern/{n;N;N;N;N;d}' file.txt

14
+NパターンはGNU拡張機能であることに注意してください。最初の変更nにはN、それは、パターンの行を含める作るためにあなたの第二の例では。
追って通知があるまで一時停止。

2
パターンが一致した後にすべての行を削除する方法は?sed -e '/ <!-#content end-> </ div> /、$ d' out.txtを使用していますが、次のエラーが表示されます:sed:-e expression#1、char 24:余分な文字コマンドよろしくお願いします。
N mol

8
何が起こっているかは似ていますが、少しずつ異なります。最初のレシピで/pattern/,+5は、「パターン」を含む行で始まり(/pattern/)、5行後に終了する()範囲を定義します+5。最後の文字dは、その範囲の各行で実行するコマンド、つまり「削除」です。代わりに範囲を一致させる第二のレシピでは、それは(パターンを含むだけ行に一致し/pattern/)、次いで、一連のコマンド実行:{n;N;N;N;N;d}、基本的に次の行を(プリントn)した後、読み出し、最終的に次の4つのライン(廃棄N;N;N;N;d)。
pimlottc 2013年

18
マック/ OS Xシステムでは、あなたは閉じ括弧の前にセミコロンを追加する必要がありますsed -e '/pattern/{n;N;N;N;N;d;}' file.txt
AVL

1
TO:完全性のために特定のパターン、次のすべての行を削除して something実行しますsed -E '/^something$/,$d'。ここで、-EPOSIXの移植は、正規表現を拡張しています。
not2qubit 2018年

7

GNU拡張機能なし(例:macOS):

パターンの後ろの5行を削除するには(パターンのある行を含む)

 sed -e '/pattern/{N;N;N;N;d;}'

追加-i ''してインプレイス編集します。


6

シンプルなawkソリューション:

一致する行の検索に使用する正規表現がシェル変数$regexに格納され、スキップする行の数が格納されていると仮定し$countます。

一致する行スキップする必要がある場合($count + 1行はスキップされます):

... | awk -v regex="$regex" -v count="$count" \
  '$0 ~ regex { skip=count; next } --skip >= 0 { next } 1'

場合、一致する行がべきではないスキップされ$count後のマッチはスキップされます)。

... | awk -v regex="$regex" -v count="$count" \
  '$0 ~ regex { skip=count; print; next } --skip >= 0 { next } 1'

説明:

  • -v regex="$regex" -v count="$count"同じ名前のシェル変数にawk基づいて変数を定義します。
  • $0 ~ regex 対象ラインに一致
    • { skip=count; next }スキップカウントを初期化して次の行に進み、一致する行を効果的にスキップします。2番目のソリューションでは、printbefore nextはそれがスキップされないようにします。
    • --skip >= 0 (まだ)> = 0の場合、スキップカウントをデクリメントしてアクションを実行し、手元の行をスキップする必要があることを意味します。
    • { next } 次の行に進み、効果的に現在の行をスキップします
  • 1は、の一般的な省略形です{ print }。つまり、現在の行が単に印刷されます
    • 一致せず、スキップされない行のみがこのコマンドに到達します。
    • 理由1と同等であるが{ print }それはある1定義によって常に(ブロック)は、その関連付けられたアクションが無条件に実行されることをその手段、真と評価されていることを示すブールパターンとして解釈されます。この場合、関連付けられたアクションがないため、awkデフォルトでは行を印刷します。

3

これはあなたのために働くかもしれません:

cat <<! >pattern_number.txt
> 5 3
> 10 1
> 15 5
> !
sed 's|\(\S*\) \(\S*\)|/\1/,+\2{//!d}|' pattern_number.txt |
sed -f - <(seq 21)
1 
2
3
4
5
9
10
12
13
14
15
21

10
うわー、それは不可解です。
pimlottc 2013年

3
賢い(GNU-Sed固有の)ソリューションですが、説明を追加しない限り、その恩恵を受ける人はほとんどいません。 pattern_number.txt1列目に一致するパターンを含む2列のファイルで、2列目にはスキップする行数。最初のsedコマンドsedは、対応するマッチングとスキップを実行するスクリプトにファイルを変換します。このスクリプトは-f、stdin(-)を介して2番目のsedコマンドに提供されます。2番目のsedコマンドは、の出力から形成されたサンプルのアドホック入力ファイルを操作して、seq 21それが機能することを示します。
mklement0

また、ソリューションには1つの注意事項があります。最初の行(パターンに一致する行)をスキップしない方法には、範囲内の重複する行もスキップしないという副作用があります。
mklement0

それは、sedの印象的な使用法です。
Travis Rodman 2016年

3

Perlの使用

$ cat delete_5lines.txt
1
2
3
4
5 hello
6
7
8
9
10
11 hai
$ perl -ne ' BEGIN{$y=1} $y=$.  if /hello/ ; print if $y==1 or $.-$y > 5 ' delete_5lines.txt
1
2
3
4
11 hai
$

2

このソリューションでは、パラメーターとして「n」を渡すことができ、ファイルからパターンを読み取ります。

awk -v n=5 '
    NR == FNR {pattern[$0]; next}
    {
        for (patt in pattern) {
            if ($0 ~ patt) {
                print # remove if you want to exclude a matched line
                for (i=0; i<n; i++) getline
                next
            }
        }
        print
    }
' file.with.patterns -

「-」という名前のファイルはawkの標準入力を意味するため、これはパイプラインに適しています


2
awkは、私が実現したよりもはるかにperlのように機能することができます!
Martin DeMello
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.