awk アクションを実行する前に入力をフィルタリングするのは良い考えでしょうか?

awk アクションを実行する前に入力をフィルタリングするのは良い考えでしょうか?

何らかの入力がある場合、アクションを実行する前にデータをフィルタリングしたほうがよいでしょうかawk、それとも ですべてのフィルタリングを実行する必要がありますかawk?

たとえば、次の入力があるとします。

$ echo "foo\nbar\nbaz"
foo
bar
baz

実行する必要がありますか:

$ echo "foo\nbar\nbaz" | sed 1q | awk '{ print $0 " cats" }'
foo cats

または:

$ echo "foo\nbar\nbaz" | awk 'NR == 1 { print $0 " cats" }'
foo cats
  • なぜどちらか一方を実行する必要があるのでしょうか?
  • 別のツールを使うべきでしょうか?
  • どのような要素を考慮すべきでしょうか?
  • これらの要因をどのようにテストできますか?

答え1

この特定のケースでは、2 番目のオプションの方が適しています。

一般的に、パイプライン内のユーティリティの数を最小限に抑える方が効率的です。不要なプロセスをフォーク(開始)しないのが最善です(最初の例のように不要なプロセスsed)。インターネットでは、次のような苦情の例を見つけるのは難しくありません。猫の無駄な使い方

最近の Unix 系システム*のほとんどでは、フォークは非常に効率的に実行されますが、開始されるプロセスのサイズに依存します。たとえば、 または の起動はperlまたはよりpythonもはるかに遅くなります。sedawk

一度限りのコマンドの場合、これはそれほど重要ではありませんが、パイプラインがループ内にあり、何度も実行される場合は、パイプラインから不要なプロセスを削除すると、全体の実行時間が大幅に短縮される可能性があります。

具体的な質問

なぜどちらか一方を実行する必要があるのでしょうか?

どちらか一方の構文に慣れている場合は、最も慣れているツール/言語を使用する方がコードの読みやすさ (および保守性) が向上する可能性があります。

別のツールを使うべきでしょうか?

この特定のケースでは、そうは思わない。 とawkはどちらもsedこの種の仕事に適したツールです。

どのような要素を考慮すべきでしょうか?

複数のファイルを処理する必要がある場合(たとえば、ループ内)、速度と効率が重要になります。

時々 1 つの大きなファイルを処理するだけの場合は、コードの読みやすさがより重要になる可能性があります。

これらの要因をどのようにテストできますか?

Bash のシェル組み込みとして利用できるユーティリティを使用してtime、さまざまなバージョンをプロファイルできます。また、スタンドアロンの実行可能プログラムとしても利用できます。たとえば、2 つのサンプル コマンドを実行すると、最初の例の方が 2 番目の例よりも 0.012 秒長くかかったことがわかります。

$ time echo "foo\nbar\nbaz" | sed 1q | awk '{ print $0 " cats" }'
foo\nbar\nbaz cats

real    0m0.056s
user    0m0.000s
sys     0m0.045s

$ time echo "foo\nbar\nbaz" | awk 'NR == 1 { print $0 " cats" }'
foo\nbar\nbaz cats

real    0m0.044s
user    0m0.000s
sys     0m0.031s

プロファイリング ベンチマークはシステム負荷やその他の制限要因の影響を受けるため、どのバージョンが他よりも高速であるかを正確に把握するには、これを何度も繰り返す必要があることに注意してください。


* MS Windowsでは、フォークよりコストがかかるため、Cygwin などの環境で実行する場合には、開始されるプロセスの数を最小限に抑えることが効果的です。

答え2

使うだけで十分ですawk(またはsed) ツールはこのような単純なケースには適していません。複数のツールを組み合わせると、複雑になりすぎて冗長になることがよくあります。

echo -e "foo\nbar\nbaz" | awk 'NR==1{print $0" cats"}'

出力:

foo cats

どのような要素を考慮すべきでしょうか?

必要なテキスト処理には複数の異なるツールの組み合わせが必要であることを確認し、そうでない場合は1つの個別のツールの力を活用する

入力文字列の最初の単語の前に特定の単語を追加するだけの場合、これも簡単です。sed道具:

echo -e "foo\nbar\nbaz" | sed 's/^.*$/& cats/; 1q'
foo cats

echo -eフラグ「eバックスラッシュエスケープの解釈を有効にする」


いずれにせよ、入力テキストの複雑さとテキスト処理ルールの洗練度によって異なります。

関連情報