6

こんにちは、awk コマンドを使用して正規表現が見つかった後、5 行を印刷しようとしています。私は次のものを持っています:

line_start=$(awk '/regex/{print NR}' file)
let line_end=$line_start+4
awk 'NR==$line_start, NR==$line_end' file

これは何も印刷しません。ハングせず、次の行に進むだけです。

同様の問題をいくつか調査したところ、人々が -v オプションを使用しているのを見ました。ここでそれを使用することになっていますが、彼らの状況はより大きな awk スクリプトの場合でした。

ちなみに私はコーンシェルを使っています

ありがとう!

4

2 に答える 2

14

スクリプトにはいくつかの問題があります。当面の問題は、awk への 2 回目の呼び出しで、スクリプトを一重引用符で囲んでいるため$line_start$line_endシェルによって変数が展開され、スクリプトの一部として文字通り awk に渡されることです。代わりに二重引用符を使用すると、これを修正できます。

awk "NR==$line_start, NR==$line_end" file

これは、$line_start$line_endが数字であるためにのみ機能します。それらが文字列の場合、これを行うことはできません。シェル変数の値は、文字列としてではなく、awk コードの一部として awk によって解析されることになるためです。一般に、文字列を awk スクリプトに渡すには、イディオム with を使用し-vて、シェル変数と同じ名前 (または必要に応じて別の名前) で awk 変数を定義できます。

awk -v "line_start=$line_start" -v "line_end=$line_end" 'NR==line_start, NR==line_end' file

スクリプトにはさらに問題があります。

  • ファイルを 2 回解析します。ファイルが大きい場合、これは遅くなる可能性があり、データがディスク ファイルではなくパイプから来る場合は不可能です。
  • に複数の一致がある場合は/regex/$line_start行番号のリストが含まれます。シェルは、そのlet行で構文エラーを報告します。

一致後に 5 行を表示する場合は、awk 内でカウントを行います。

awk '
  /regex/ { show_lines = 5 }
  show_lines { print; --show_lines; }
' file

最初に一致したブロックのみを表示したい場合は、show_lines0 に達したら終了します。

  show_lines { print; --show_lines; if (!show_lines) exit; }
于 2012-08-31T16:12:37.360 に答える
2

これには sed を使用できます。

sed -n '/regex/{N;N;N;N;N;p}' file

または awk ソリューションを変更します。

line_start=$(awk '/regex/{print NR}' file) 
let line_end=$line_start+4 
awk "{ if (NR>=$line_start && NR<=$line_end) print; }" file

別の awk ソリューション(s.awk):

BEGIN           { v = -1} 
/regex/         { v = 0 } 
v > -1          { v++   }
v > -1 && v < 5 { print }
v == 5          { exit  }

使用する:

awk -f s.awk file
于 2012-08-31T15:46:24.177 に答える