コマンドラインで一致する値をどのように検索して印刷できますか?

コマンドラインで一致する値をどのように検索して印刷できますか?

たとえば、次の文字列があります。

2017-01-19:31:51 [ABCD:] 37723 - MATCH: 10 [text]

MATCH検索を使用して値10を印刷したいですawk。従来の方法を使用してこれを行うことはできますが、またはを使用してgrep方法cutを探したいと思います。sedawk

MATCH行はどこにでもあります。

答え1

sed -n 's/.* MATCH: \([^ ]*\).*/\1/p'

" MATCH: "一致する各行の右端にある空白以外の文字シーケンスを印刷します。

-nsedデフォルトでは印刷されないパターンスペースを指定します。置換が成功すると、コマンドpのフラグはパターン空間(つまり代替結果)をs印刷するように指示します。sed

だから:

sed -n 's/pattern/replacement/p'

正常な代替結果を印刷する一般的な慣用語です。

上記は、入力が有効なテキストであると仮定しています。なぜなら、.*どのシーケンスとも一致するからです。数値、有効な文字を形成しないバイトシーケンスと一致しません。これは通常、テキストが別のエンコーディングで処理されるときにUTF-8ロケールで発生します。このような状況が発生した場合は、上記の行の前に追加してくださいLC_ALL=C。これにより、sed各バイトが文字として扱われるため、誤ったバイトシーケンスが発生する可能性はありません。ここでは、一致する文字がすべてポータブル文字セットに属するため、機能します。

標準には、その機能がawkキャプチャグループ(キャプチャイン)をサポートしていないため、対応する項目はありません。\(...\)\1sub()

ここでは、次の機能を使用する必要がありますmatch()

awk 'match($0, / MATCH: [^ ]*/) {
       print substr($0, RSTART+8, RLENGTH-8)}'

または、次の技術を使用してください。

awk -F ' MATCH: ' 'NF>1 {sub(/ .*/, "", $2); print $2}'

(考える方は参考にしてください。一番左起こった" MATCH: ")。

GNUには、コマンドと同様の機能がありますawkが、置き換えが行われたかどうかを知らせないという設計バグがあります。ここでは、次のことができます。gensub()seds

 gawk '(replacement = gensub(/.* MATCH: ([^ ]*).*/, "\\1", 1)) != $0 {
   print replacement}'

答え2

すべての行の形式が同じであると仮定すると(または少なくとも含まれるすべての行MATCH:)、行の5番目の要素のように見え、MATCH:必要な値は6番目の要素です。

したがって、awkは5番目の要素が同じかどうかをテストし、MATCH:そうであればその行の6番目の要素を印刷します。

$ echo "2017-01-19:31:51 [ABCD:] 37723 - MATCH: 10 [text]" |awk -e '{ if ($5 == "MATCH:") print $6 }' 
    10

編集:仮説が行の任意MATCH:の場所にある可能性があることを考慮すると、次のようになります。

  $ echo "2017-01-19:31:51 [ABCD:] 37723 - MATCH: 10 [text]" |awk -e '{ for (x=1; x<NF; x++ ) { if ($x == "MATCH:") {x=x+1; printf("%s\n", $x); break}}}' 
10

非常にエレガントではないかもしれませんが、行のすべてのフィールドを繰り返し、各フィールドをテストする必要があります。これはループforとテストでif行われます。テストフィールドが一致すると、次のフィールドが印刷されます。

次の行に直接移動し、現在のフィールドの繰り返しを続行するために中断を追加しました。

複数行ファイルの場合:

$ cat terst 
2017-01-19:31:51 [ABCD:] 37723 - MATCH: 10 [text]
2017-01-19:31:51 [ABCD:] 37723 - MATCH: 11 [text]
2017-01-19:31:51 [ABCD:] 37723 - [text]
2017-01-19:31:51 37723 - MATCH: 12 [text]
$ awk -e '{ for (x=1; x<NF; x++ ) { if ($x == "MATCH:") {x=x+1; printf("%s\n", $x); break}}}' terst 
10
11
12

関連情報