web-dev-qa-db-ja.com

パターンを見つけて、その前の2行とその後の1行の先頭に#を挿入します

私は大きなファイル(2000行以上)を持っています。パターンを見つけた後、行の上の2の先頭と行の下の1の先頭に#を挿入する必要がある場合。また、パターンが見つかった行の先頭に#を挿入します。環境はRedHatLinuxです。また、あなたが説明できれば、それは素晴らしいことです。

例を見てください。以下のテキストを参照してください。「失敗」を検索し、その前の2行とその文字列の後の1行(行の先頭)を検索します。また、文字列「Fail」を含む#行。

Name
Number
Reason = Pass
Reasult
Name
Number
Reason = Pass
Reasult
Name
Number
Reason = Fail
Reasult
Name
Number
Reason = Pass
Reasult
Name
Number
Reason = Fail
Reasult
Name
Number
Reason = Pass
Reasult
3
Randy

Perlを使用することをお勧めします:

Perl -p0e 's/(.*\n)(.*\n)(.*Fail\n)/#\1#\2#\3#/g' file

仕組みは次のとおりです。

  • -p:すべての入力行にわたってループ内のプログラムを出力します
  • -0:レコード区切り文字としてnullを想定
  • -e:コマンドラインからプログラムを実行する
  • s/x/y/g:ファイル内の任意の場所でxをyに置き換えます
  • ():正規表現をグループ化する
  • .*:改行以外の任意の文字が0回以上繰り返された
  • \n:改行
  • \1\2\3:n番目のグループからのアクセスパターン()

出力:

Name
Number
Reason = Pass
Reasult
Name
Number
Reason = Pass
Reasult
#Name
#Number
#Reason = Fail
#Reasult
Name
Number
Reason = Pass
Reasult
#Name
#Number
#Reason = Fail
#Reasult
Name
Number
Reason = Pass
Reasult
3
jimmij

これは、スライディングウィンドウを使用したsedソリューションです(したがって、パターンスペースに一度に4行を超えることはありません)。

sed '1{N;N;};$!N;/.*\n.*\n.*Fail.*\n.*/{s/^/#/;s/\n/&#/g;};P;D' infile

最初の行で、Nextに2行を読み取ります(したがって、パターンスペースに3行あります)。
次に、各入力行(最初の行を含む)に対して、Next行をプルします(したがって、パターン空間に4行あります)。パターン空間の3行目がFailと一致する場合、パターン空間の各行の前に#が付きます。次に、関係なく、最初の\newlineまでPrintsし、次に最初の\newlineまでDeletesして、サイクルを再開します。

1
don_crissti

Perlで4行の「ウィンドウ」を使用する:

Perl -ne '
    Push @w, $_;
    if (4 == @w) {
        if ($w[2] =~ /Fail/) {
            s/^/#/ for @w;
        }
        print @w;
        @w = ();
    }
' < input-file > output-file
  • -nは入力を1行ずつ読み取ります。
  • @wはウィンドウで、4行になるまで行を累積します。その時点で、3番目の行は/Fail/と照合され、存在する場合は、ウィンドウの各行の前に#が付けられます。次に、ウィンドウが印刷されて空になります。

注:最後のブロックが4行より短い場合、入力の最後の行が印刷されない場合があります。

0
choroba

楽しみのために:これは、問題を解決するedインタラクティブラインエディタ上のシェルループです。

while ed text.in <script.ed >/dev/null; do
  :  # nothing here
done

ファイルscript.edには

/^[^#].*Fail/-2
.,+3s/^/#/
w
  1. 編集スクリプトの最初の行は、まだ#が付加されていないWordFailを含む次の行を見つけ、そこから2行戻ります。

  2. スクリプトの2行目は、現在の行とさらに3行先の行について、行の先頭を#に置き換えます(つまり、行の前に#を追加します)。

  3. スクリプトの3行目は、ファイルをディスクに書き戻します。

シェルのループは、edがゼロ以外の終了ステータスで終了するとすぐに終了します。これは、編集スクリプトの1行目の正規表現に一致する別の行が見つからない場合に発生します。

または、ファイルに個別の編集スクリプトを含まない場合:

while ed text.in >dev/null <<ED_END
/^[^#].*Fail/-2
.,+3s/^/#/
w
ED_END
do
  :  # nothing here
done
0
Kusalananda

@ don_crissti のスクリプトのより単純化されたバリアント

sed ':a;/\(.*\n\)\{2\}/{P;D};N;/= Fail$/! ba;N;s/^/# /gm'
0
Costas
_$ sed -r 'H;1h;$!d;x; s/\n([^\n]*)\n([^\n]*)\n([^\n]*Fail[^\n]*)\n/\n#\1\n#\2\n#\3\n#/g' file
Name
Number
Reason = Pass
Reasult
Name
Number
Reason = Pass
Reasult
#Name
#Number
#Reason = Fail
#Reasult
Name
Number
Reason = Pass
Reasult
#Name
#Number
#Reason = Fail
#Reasult
Name
Number
Reason = Pass
Reasult
_

使い方

  • _H;1h;$!d;x_

    これらのコマンドは、ファイル全体をで読み取ります。

  • s/\n([^\n]*)\n([^\n]*)\n([^\n]*Fail[^\n]*)\n/\n#\1\n#\2\n#\3\n#/g

    これにより、3行目にFailが含まれる4つの連続した行が検索されます。それが見つかった場合は、各改行文字の後に_#_が配置されます。

    より詳細には、代替コマンドは_s/old/new_のようになります。ここで、oldは正規表現です。私たちの場合、それは\n([^\n]*)\n([^\n]*)\n([^\n]*Fail[^\n]*)\nです。それを4つの部分に分けてみましょう。

    1. \n([^\n]*)は最初の行を見つけて、グループ1に保存します。

    2. \n([^\n]*)は2行目を見つけて、グループ2に保存します。

    3. \n([^\n]*Fail[^\n]*)は3行目を検索しますが、この行に単語Failが含まれている場合にのみ一致します。

    4. _\n_は4番目の改行に一致します。 (4行目のテキストは保存されません。必要ありません。)

    4行が上記と一致する場合、それらを_\n#\1\n#\2\n#\3\n#_に置き換えます。これは、各改行文字_#_の後に_\n_が追加されることを除いて、入力と同じです。

    Mac OSX(BSD)

上記はGNU sedでテストされました。BSDsedを使用している場合は、以下を試してください。

_sed -E 'H;1h;$!d;x; s/\n([^\n]*)\n([^\n]*)\n([^\n]*Fail[^\n]*)\n/\n#\1\n#\2\n#\3\n#/g' file
_
0
John1024