awkのマルチパターンマッチングについて理解できない小さな問題があります。次のawk行があります。
awk '/pat1/{v1=$4; next} /pat2/{v2=$5; next} /pat3/{v3=$6;next} /pat4/{v4=$5; print v1," ",v2," ",v3" ",v4}' myfile.out
これはすべて一致するため、私が望む結果(各一致に対して1行に数学結果を印刷)を提供します。パターンの1つが存在しない場合は、何も一致しません。
したがって、すべてが一致すると、期待した結果が得られます。
pat1 pat2 pat3 pat4
pat1 pat2 pat3 pat4
pat1 pat2 pat3 pat4
pat1 pat2 pat3 pat4
.
.
.
各行ごとにpatX
異なる値があります!
このスペースを空にしていないように見える場合は、awkにこれらのパターンを見つけるように指示する方法はありますか?
たとえば、最初のインスタンスで更新されている文書にpat3
まだ存在しない場合は、次のようにします。pat4
pat1 pat2
pat1 pat2 pat3 ------> (here let's assume that pat3 has made an appearange)
pat1 pat2 pat3 pat4 ------> (here pat4 started to appear too)
pat1 pat2 pat3 pat4
pat1 pat2 pat3 pat4
.
.
.
awkでできますか?
編集:以下は私が直面している2つの例のシナリオです。私のファイルは空の状態で始まり、いくつかのパターンをフィルタリングする必要があるデータで埋められます。すべてのパターンが最初から現れるわけではありません。したがって、ファイルは次のように始まります。
some text here pat1
some more text here
some more text here pat2
some more text here and pat3
上記のawkコマンドを使用すると、pat4
まだ存在しないため、空の結果が得られます。時間が経つと結局現れます。
some text here pat1
some more text here
some more text here pat2
some more text here and pat3
some more text here pat4
some text here pat1
some more text here
some more text here pat2
some more text here and pat3
some more text here pat4
some text here pat1
some more text here
some more text here pat2
some more text here and pat3
some more text here pat4
このコマンドの結果はawk
期待どおりに表示されます。
pat1 pat2 pat3 pat4
pat1 pat2 pat3 pat4
pat1 pat2 pat3 pat4
しかし、最初に得たかった結果は次のとおりです。
pat1 pat2 pat3
今より明確になることを願っています。 (上記のawkコマンドをより簡単にするために再構築してテストしました。)
答え1
次のようなものが必要なようです。
$ cat tst.awk
BEGIN { OFS=" " }
{ sub(/\r$/,"") }
( ($NF ~ /pat1/) && (state == 0) ) ||
( ($NF ~ /pat2/) && (state == 1) ) ||
( ($NF ~ /pat3/) && (state == 2) ) ||
( ($NF ~ /pat4/) && (state == 3) ) {
v[++state] = $NF
}
state == 4 {
print v[1], v[2], v[3], v[4]
state = 0
}
$ awk -f tst.awk file
pat1 pat2 pat3 pat4
pat1 pat2 pat3 pat4
pat1 pat2 pat3 pat4
答え2
おそらくEND句を使用して結果を印刷することもできます。
awk '/pat1/{v1=$4; next} /pat2/{v2=$5; next} /pat3/{v3=$6; next} /pat4/{v4=$5;} END{ print v1," ",v2," ",v3" ",v4 }' myfile.out
答え3
私の質問に@EdMortonの答えを適用しようとしている間、私は以前に誰かから必要な情報を見つけました。ワイヤー彼は答えを提供し、問題を完全に解決しました。これが私の解決策です。
awk '/pat1/{v1=$4; next}{v1="xxx"} /pat2/{v2=$5; next}{v2="xxx"} /pat3/{v3=$6;next}{v3="xxx"} /pat4/{v4=$5}{v4="xxx"} {print v1," ",v2," ",v3" ",v4}' myfile.out
パターンの1つがまだ存在しない場合は、xxx
その場でパターンを探してみましょう。xxx
単一の空白文字または異なる値に置き換えることができます。
すべてのアドバイスと助けに感謝!
PS:時々問題を説明するために入力例を提供するのは簡単ではないことがわかりました。これで失望したらすみません!
答え4
Raku(以前のPerl_6)の使用
raku -e 'my @a; my @pat = <<pat1 pat2 pat3 pat4>>; for lines() { for @pat -> $i { @a.push( m[$i] // " __ " ) };}; .put unless $_ eq " __ __ __ __ " for @a.rotor(4);'
トリッキーな質問のためラクから回答しました。 1行に必要な項目が2つ以上含まれている場合はどうなりますかpattern
?それともpattern
誤動作がありますか?以下のコードはこれらのケースを処理します(パターンが見つからない行も削除します)。
サンプル入力の最後の数行とサンプル出力の最後の数行から抽出されたパターンを見てください。 (以下の例では空行を削除しました。)
入力例:
some text here pat1
some more text here
some more text here pat2
some more text here and pat3
some more text here
some text here pat1
some more text here
some more text here pat2
some more text here and pat3
some more text here pat4
some text here pat1
some more text here
some more text here pat2
some more text here and pat3
some more text here pat4
some more text here pat1 pat2
some more text here pat1 pat2 pat3 pat4
出力例:
pat1 __ __ __
__ pat2 __ __
__ __ pat3 __
pat1 __ __ __
__ pat2 __ __
__ __ pat3 __
__ __ __ pat4
pat1 __ __ __
__ pat2 __ __
__ __ pat3 __
__ __ __ pat4
pat1 pat2 __ __
pat1 pat2 pat3 pat4
注:一般的な状況は次のとおりです。いいえ上記のコードは、行の複数のコピーで単一のパターンが見つかった場合を処理します。上記のコードには、発生回数を計算するメカニズムはなく、パターンが「表示されているか」だけを伝えます。以下の例:
echo "text here pat2 pat2 pat2 pat4" | raku -e 'my @a; my @pat = <<pat1 pat2 pat3 pat4>>; for lines() { for @pat -> $i { @a.push( m[$i] // " __ " ) };}; .put unless $_ eq " __ __ __ __ " for @a.rotor(4);'
繰り返しパターン出力:
__ pat2 __ pat4