パターンの上の行の範囲をsed(またはawk)で削除します


28

パターンbananaを持つ行とその後の2行を削除する次のコードがあります。

sed '/banana/I,+2 d' file

ここまでは順調ですね!しかし、私はそれを bananaに2行削除する必要がありますが、「マイナス記号」または何でも取得することはできません(何をgrep -v -B2 banana fileすべきかと同様ですが):

teresaejunior@localhost ~ > LC_ALL=C sed '-2,/banana/I d' file
sed: invalid option -- '2'
teresaejunior@localhost ~ > LC_ALL=C sed '/banana/I,-2 d' file
sed: -e expression #1, char 16: unexpected `,'
teresaejunior@localhost ~ > LC_ALL=C sed '/banana/I,2- d' file
sed: -e expression #1, char 17: unknown command: `-'

1
最も簡単な方法は、すべてのデータを配列にロードし、不要な行をスキップして、残りを出力することですawk '{l[m=NR]=$0}/banana/{for(i=NR-2;i<=NR;i++)delete l[i]}END{for(i=1;i<=m;i++)if(i in l)print l[i]}'。これは効率的ではないため、これは単なるヒントであり、解決策ではありません。
マナトワーク

6
ただやるtac file | sed ... | tac。:P
アンガス

@angus私はそれについて考えませんでした;)
テレサeジュニア

1
あなたが行っている可能性がありsed '/banana/,+2d' file 、その意志も仕事
Akaks

1
awkを使用することにオープンである場合、それは非常に簡単です: awk 'tolower($0)~/bandana/{print prev[!idx];print prev[idx]} {idx=!idx;prev[idx]=$0}' filein これはコメントであり、回答ではないため(すでに他の回答があります)、あまり詳細に説明しませんが、それの核心は常にあなたが持っていることです前の二つの前のレコード[0]とPREV [1]、これの繰り返しではなく、常にに応じて、「新鮮な」prev[idx]あなたは印刷するときに、あなたがで印刷、!idxそしてidxオーダー。とにかく、交互idxに、現在のレコードをに入れprev[idx]ます。
Luv2code

回答:


22

Sedはバックトラックしません。1行が処理されると完了します。したがって、「行を見つけて次のN行を印刷する」とは異なり、「行を見つけて前のN行を印刷する」はそのままでは機能しません。

ファイルが長すぎない場合は、GNU拡張機能で問題ないように見えるのでtac、ファイルの行を逆にするために使用できます。

tac | sed '/banana/I,+2 d' | tac

別の攻撃の角度は、awkのようなツールでスライディングウィンドウを維持することです。からの適応grepの-A -B -Cスイッチに代わるものはありますか(前後の数行を印刷するため)?(警告:最小限のテスト):

#!/bin/sh
{ "exec" "awk" "-f" "$0" "$@"; } # -*-awk-*-
# The array h contains the history of lines that are eligible for being "before" lines.
# The variable skip contains the number of lines to skip.
skip { --skip }
match($0, pattern) { skip = before + after }
NR > before && !skip { print NR h[NR-before] }
{ delete h[NR-before]; h[NR] = $0 }
END { if (!skip) {for (i=NR-before+1; i<=NR; i++) print h[i]} }

使用法: /path/to/script -v pattern='banana' -v before=2


2
sedスライディングウィンドウも実行できますが、通常、結果のスクリプトは非常に読みにくいため、単に使用する方が簡単awkです。
jw013

@Gilles .. awkスクリプトは正しくありません。現状のままでは、空白行が印刷され、最後の行が欠落します。これはそれを修正するように見えますが、理想的でも正しくないかもしれません:if (NR-before in h) { print...; delete...; }...そしてENDセクション:for (i in h) print h[i]...また、awkスクリプトは一致する行を出力しますが、tac/secバージョンはそうではありません。しかし、問題は、この上のビット曖昧です..「オリジナル」awkスクリプトは、あなたがリンクを提供したし、私はそれのように...私は必ず上記の「MOD」はどのように影響するかないんだけど...罰金を作品の後に印刷を行...
Peter.O

@ Peter.Oおかげで、awkスクリプトは改善されたはずです。そして、6〜8年もかかりませんでした。
ジル 'SO-悪であるのをやめる'

19

これはexまたはvim -eを使用すると非常に簡単です

    vim -e - $file <<@@@
g/banana/.-2,.d
wq
@@@

式は次のとおりです。現在の行-2から現在の行までの範囲にバナナを含むすべての行について、削除します。

クールなのは、範囲に後方検索と前方検索も含めることができることです。たとえば、これは、リンゴを含む行で始まり、オレンジを含む行とバナナを含む行で終わるファイルのすべてのセクションを削除します。

    vim -e - $file <<@@@
g/banana/?apple?,/orange/d
wq
@@@

7

次の「スライディングウィンドウ」を使用しますperl

perl -ne 'push @lines, $_;
          splice @lines, 0, 3 if /banana/;
          print shift @lines if @lines > 2
          }{ print @lines;'

6

あなたはこれをかなり簡単に行うことができますsed

printf %s\\n    1 2 3 4match 5match 6 \
                7match 8 9 10 11match |
sed -e'1N;$!N;/\n.*match/!P;D'

私は、誰もがそう言う理由を知りませんが、する前の行を行を見つけ、印刷 sed組み込んだビルトインP最初にまでしか書き込むRINTプリミティブ\nパターンスペースにewline文字。補完的なDeleteプリミティブは、パターンスペースの同じセグメントを削除してから、スクリプトを残りのもので再帰的にリサイクルします。そして、四捨五入Nするために、挿入された\newline文字に続くパターンスペースにext入力行を追加するためのプリミティブがあります。

そのため、sed必要なのは1行だけです。あなたのmatch正規表現が何であれ、あなたは黄金に変わります。それは非常に高速なソリューションでもあるはずです。

また、直前の2行の出力をクワイエットするトリガー、その印刷をクワイエットするトリガーの両方として、match直前の行を正しくカウントすることにも注意してください。match


1
7match
8
11match

任意の行数で機能するために必要なことは、リードを獲得することだけです。

そう:

    printf %s\\n     1 2 3 4 5 6 7match     \
                     8match 9match 10match  \
                     11match 12 13 14 15 16 \
                     17 18 19 20match       |
    sed -e:b -e'$!{N;2,5bb' -e\} -e'/\n.*match/!P;D'

1
11match
12
13
14
20match

...一致する前の5行を削除します。


1

を使用してman 1 ed

str='
1
2
3
banana
4
5
6
banana
8
9
10
'

# using Bash
cat <<-'EOF' | ed -s <(echo "$str")  | sed -e '1{/^$/d;}' -e '2{/^$/d;}'
H
0i


.
,g/banana/km\
'm-2,'md
,p
q
EOF
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.