awk forループで文字列を連結してEND部分で印刷する方法

awk forループで文字列を連結してEND部分で印刷する方法

質問: "「ENDセクションで印刷された変数には、すべての行ではなく最後に見つかった行だけがあります。

ファイル1:

pattern .........
irrelevant text
irrelevant text
pattern .........
pattern .........
irrelevant text

奇妙なコード:

awk '{ for (i=1; i<=NR; i++)
       if ($i ~ /^pattern/) a+=$0 
     }
     END {print $a}' file1

END部分でパターンのある行だけを印刷したいと思います。

答え1

特定のパターンに一致するすべての行を収集し、最後に印刷したいようです。

あなたはこれを行うことができます

awk '/^pattern/ { a[++n] = $0 }
     END { for (i = 1; i <= n; ++i) print a[i] }' file

これはa配列として機能し、パターンに一致する各行を配列の新しい項目として追加します。最後に繰り返された項目を繰り返し、a各項目を印刷します。

pattern行全体の正規表現を一致させるのではなく、最初の列で正しいリテラル文字列を見つけるには、$1 == "pattern"as条件を使用します。

しかし、これがみんなやりたいことをすれば使いやすくなります

awk '/^pattern/' file

patternまたは、最初の列のリテラル文字列と一致させたい場合

awk '$1 == "pattern"' file

これにより、パターンに一致する各行の基本操作が呼び出されます。pattern2番目のバリアントを使用する場合は、それを最初の列として含めます。 「デフォルト動作」は行を印刷することです。


では、現在行の値を増加させるawk算術演算となり、a += $0数値として解釈されます。alineを文字列として変数に連結するには、または追加された文字列の前に改行文字を挿入する場合(デフォルト)をa使用できます。しかし、私は何もここでやりたいことではないと思います。a = a $0a = a ORS $0ORS

答え2

コードにはいくつかの問題があります。

  1. 一致するパターンをテストするためにファイル内のすべての行にアクセスしようとしますが、{ ... }これをルールブロック()内で実行します。ただし、すべてのルールが処理されます。ファイルの各行について、これらのルールでは、現在処理されている行の内容にのみアクセスできます。パスワード

    { for (i=1; i<=NR; i++)
       if ($i ~ /^pattern/) a+=$0 
    }
    

    したがって、(条件が前に来ていないため、ファイル内のすべての行に対して)テストを試みます。フィールド1番からNR- どこNRファイル内の現在の行の行番号、現在行のフィールド数の代わりにNF追加してみてください。現在の行全体aこれが発生するたびに変数を指します。パターンが正規表現で提案された行の先頭にしか現れないことが事実である場合(アンカーのため)、結果はめちゃくちゃになることはできませんが、^少なくとも非常に非効率的です。

  2. 現在行を に追加しようとしている間、a次のように書き込みます。

    a+=$0
    

    ただし、これは行(または少なくともスペースで区切られた最初のフィールド)が数値として正しく解釈できる場合にのみ明確に定義され、この場合はa/で始まるすべての行にのみ表示されます。ファイルに表示される個々の番号。行を数値として解釈できない場合、a最終値は「0」です。

  3. ENDブロックで宣言

    print $a
    

    しかし、これは印刷されますフィールド番号a変数の内容ではなく、現在の行の内容ですa。ただし、変数はa「0」(ポイント2で述べたように)なので、これは現在の行全体(別名$0)を参照します。そして、ブロックのフィールド番号への参照はEND常にファイルの最後の行を参照するので(ファイルの末尾に「現在」行がないため)、このステートメントは必然的にファイルの最後の行全体を印刷し、他にはありません。

特定のパターンに一致するライン印刷にのみ興味があるように思われるので、grepこのタイプのジョブ専用ツールを使用する方が簡単になります。

答え3

最初のフィールドを持つすべての行を印刷するには、pattern内容をメモリに保存するのではなく、見つかったすべての行を印刷するだけです。

awk '$1=="pattern"' file

でも

grep -w '^pattern' file

逆に、各行を印刷するにはどのこの行のフィールドはですpattern。以下を使用してください。

awk '{ for(i=1; i<=NF; i++){ if($i=="pattern"){ print; next}}}' file

またはフィールド値のみを探している場合スタートしかし、patternその後に他の文字があるかもしれません(コードで試している文字)。最初のフィールドだけが必要な場合は、次を使用してください。

awk '$1~/^pattern/' file

これはすべての分野に適用されます。

awk '{ for(i=1; i<=NF; i++){ if($i~/^pattern/){ print; next}}}' file

答え4

あなたの質問を正しく理解したら、一致するすべての行をリンクしたい^patternので、これはあなたの要件を満たすでしょう。

echo $(grep '^pattern' infile)

awk同じ

echo $(awk '/^pattern/' infile)

またはawk単に使用してください:

awk '/^pattern/{ line = (line? line FS $0: $0) }  END{ print line }' infile

関連情報