別のオプション:ファイルを逆にして next を印刷する 条件が一致する場合の行:
tac file | awk '$1 == "BB" && $2 > 1 {getline; print}' | tac
一般性について
このクラスの問題に対する最も一般的な解決策には、次の 2 つのパスが含まれることに言及する必要があると思います。
- 各行の先頭に 10 進数の行番号 ($REC) を追加する最初のパス。$REC によって行を効果的にレコードにグループ化します
- レコード境界として $REC のそれぞれの新しい値の最初のインスタンスでトリガーする 2 番目のパス ($CURREC をリセット)。その後、一致する $CURREC に続くレコードに関するネイティブ AWK イディオムに沿って進みます。
中間ファイルでは、一連の 10 進数字とそれに続く区切り文字 (人為的な理由で、通常はタブまたはスペースが追加されます) は、ベースライン ファイルに関して帯域外として解析されます (概念的には切り捨てられます)。
コマンド ライン ペースト モンスター
コマンド ラインに限定されていても、中間ファイルがディスクにヒットしないようにするのは簡単なことです。プロセス置換をサポートする ZSH (私のお気に入り) などの高度なシェルを使用する必要があるだけです:
paste <( <input.txt awk "BEGIN { R=0; N=0; } /Header pattern/ { N=1; } { R=R+N; N=0; print R; }" ) input.txt | awk -f yourscript.awk
そのワンライナーを説明に適したものにしましょう:
P="/Header pattern/"
X="BEGIN { R=0; N=0; } $P { N=1; } { R=R+N; N=0; print R; }"
paste <( <input.txt awk $X ) input.txt | awk -f yourscript.awk
これにより、3 つのプロセスが開始されます。単純なインライン AWK スクリプト paste
、そして最初に本当に実行したかった AWK スクリプト。
<()
の舞台裏 コマンド ライン コンストラクトは、名前付きパイプを作成し、最初の入力ファイルの名前として貼り付けるパイプ名を渡します。 paste
の場合 の 2 番目の入力ファイルには、元の入力ファイルの名前を付けます (したがって、このファイルは 2 つの異なるプロセスによって順次、並行して読み取られ、その間で最大で 1 消費されます) 入力ファイルがコールドの場合は、ディスクから読み取ります)。
真ん中にある魔法の名前付きパイプは、おそらく古代の Unix が約 16 kB の平均サイズで管理していたメモリ内 FIFO です (paste
を断続的に一時停止します)。 yourscript.awk
の場合の処理 プロセスは、この FIFO を元に戻すのが遅い)。
おそらく、最近の Unix はより大きなバッファーをそこにスローします。それは可能なためです。 数百または数千のこれらを含むプロセスリダイレクトを備えた高度なコマンドライン:-)
その他のパフォーマンスに関する考慮事項
最新の CPU では、これら 3 つのプロセスすべてが別々のコアで実行されていることが容易にわかります。
これらのプロセスの最初の 2 つは、真に些細なことの境界です。単一のパターン マッチと、2 つの引数で呼び出される貼り付けを含むいくつかのマイナーな簿記を持つ AWK スクリプトです。 yourscript.awk
これらよりも速く走るのは難しいでしょう。
開発マシンには、このマスター シェル - マスター ソリューション パターンを実行ドメインでほとんど自由にレンダリングするための負荷の軽いコアがありませんか?
<ブロック引用>リング、リング。
こんにちは?
ねえ、それはあなたのためです。 2018 は電話をかけたばかりで、その問題を元に戻したいと考えています。
2020 年は正式に MTV の猶予です。それが私たちの好きなやり方です。魔法のパイプは無料で、コアは無料です。最近この分野を揺るがしている特定の TLA チップ ベンダーの名前を大声で言うまでもありません。
最終的なパフォーマンスの考慮事項として、実際のレコード番号を解析するオーバーヘッドが必要ない場合:
X="BEGIN { N=0; } $P { N=1; } { print N; N=0; }"
これで、FIFO 内の中間ファイルには、各行の先頭に追加の 2 文字 (「0」または「1」と、paste
によって追加されたデフォルトの区切り文字) だけで注釈が付けられます。 )、'1' はレコードの最初の行を示します。
名前付き FIFO
内部的には、これらは、通常のパイプ コマンドを記述したときに Unix によってインスタンス化される魔法の FIFO と同じです:
cat file | proc1 | proc2 | proc2
3 つの名前のないパイプ (および cat
に専念するプロセス全体) あなたも必要としませんでした)。
本当に例外的な シェルによって事前管理されるデフォルトの stdin/stdout ストリームの利便性は、 paste $magictemppipe1 $magictemppipe2
という現実を曖昧にします すべてのケースの 99% で、考慮する価値のある追加のパフォーマンスに関する考慮事項はありません。
"<()
を使用 Yジョイント、ルーク。」
問題領域における自然な意味論的分解に対するあなたの本能的な反射は、これによって非常に恩恵を受けるでしょう。
誰かがシェル構造に名前を付ける知恵を持っていたら <()
そもそも YODA の運営者として、少なくとも 10 年ほど前にはユニバーサル サービスを開始していたのではないかと思います。
これは一つの方法です:
$ awk '$1=="BB" && $2>1 {print f} {f=$1}' file
AAAAAAAAAAAAA
説明
$1=="BB" && $2>1 {print f}
最初のフィールドが正確にBB
の場合 2 番目のフィールドが1
より大きい 、次にf
を出力します 、保存された値。{f=$1}
現在の行をf
に保存します 、次の行を読むときにアクセスできるようにします。