web-dev-qa-db-ja.com

不要な猫を気にする必要がありますか?

多くのコマンドラインユーティリティは、パイプから、またはファイル名の引数として入力を取得できます。長いシェルスクリプトの場合、特に最初のコマンドに複数行の引数が必要な場合は、チェーンをcatで始めると読みやすくなります。

比較する

sed s/bla/blaha/ data \
| grep blah \
| grep -n babla

そして

cat data \
| sed s/bla/blaha/ \
| grep blah \
| grep -n babla

後者の方法は効率が悪いですか?もしそうなら、違いは、スクリプトが実行されるかどうか、たとえば1秒に1回実行されるかどうかを気にするのに十分ですか?読みやすさの違いはそれほど大きくありません。

53
user4518

ここにいくつかの欠点の要約があります:

_cat $file | cmd
_

以上

_< $file cmd
_
  • 最初に、メモ:上記の_$file_の周りには(意図的に説明するために)二重引用符が抜けています。 catの場合、それはzshを除いて常に問題です。リダイレクションの場合、これはbashまたは_ksh88_の場合のみの問題であり、他の一部のシェル(POSIXモードのbashを含む)の場合は(スクリプトではなく)対話型の場合のみです。
  • 最も頻繁に引用される欠点は、余分なプロセスが生成されることです。 cmdが組み込まれている場合、bashのようないくつかのシェルでは2つのプロセスです。
  • catが組み込まれているシェルを除いて、パフォーマンスの最前線にありますが、追加のコマンドも実行されます(もちろん、ロードされ、初期化されます(およびリンクされているライブラリも同様です))。
  • 依然としてパフォーマンスの最前線にある大きなファイルの場合、つまり、システムはcatプロセスとcmdプロセスを交互にスケジュールし、パイプバッファーを常にいっぱいにして空にする必要があります。 cmdが一度に_1GB_ large read()システムコールを実行する場合でも、パイプは数キロバイトを超えるデータを保持できないため、制御はcatcmdの間を行き来する必要があります。時間。
  • 一部のcmds(_wc -c_など)は、stdinが通常のファイルである場合に最適化を行うことができますが、そのstdinは単なるパイプであるため、_cat | cmd_では実行できません。 catとパイプを使用すると、ファイル内でseek()を実行できないことも意味します。 tactailなどのコマンドの場合、これはパフォーマンスに大きな違いをもたらします。つまり、catでは、入力全体をメモリに格納する必要があるということです。
  • _cat $file_、さらにその正しいバージョン_cat -- "$file"_は、_-_(または_--help_または_-_で始まるすべてのような特定のファイル名では正しく機能しません。 _--_)を忘れた場合。 catの使用を主張する場合、信頼性を高めるために、代わりに_cat < "$file" | cmd_を使用する必要があります。
  • _$file_を読み取り用に開くことができない(アクセスが拒否された、存在しない...)場合、_< "$file" cmd_は一貫したエラーメッセージ(シェルによる)およびnot runを報告しますcmd、_cat $file | cmd_はcmdを実行しますが、標準入力は空のファイルのように見えます。つまり、_< file cmd > file2_などの場合、fileを開けない場合、_file2_は破棄されません。
24

パッティング<fileパイプラインの終わりは、cat file 開始時。自然英語は左から右に読みます。

パッティング<fileパイプラインの開始も猫よりも読みにくいと私は言うでしょう。 Wordは記号、特に間違った方向を指しているように見える記号よりも読みやすくなっています。

catを使用すると、command | command | command フォーマット。

16
Jim

ここでの他の回答が直接対処していないように見えることの1つは、このようにcatを使用しても、「無関係のcatプロセスが生成されて機能しない」という意味では「役に立たない」ということです。 「不必要な作業のみを行う猫プロセスが生成される」という意味では役に立たない。

これら2つの場合:

sed 's/foo/bar/' somefile
<somefile sed 's/foo/bar/'

シェルは、somefileまたはstdin(それぞれ)から読み取るsedプロセスを開始し、次にいくつかの処理を実行します-改行に到達するまで読み取り、その行の最初の 'foo'(存在する場合)を 'bar'で置き換えてから出力しますその行をstdoutにループします。

の場合:

cat somefile | sed 's/foo/bar/'

シェルはcatプロセスとsedプロセスを生成し、catのstdoutをsedのstdinにワイヤリングします。 catプロセスはファイルから数キロバイトまたはおそらくメガバイトのチャンクを読み取り、それを標準出力に書き込みます。そこで、sed sommandが上記の2番目の例のようにそこからピックアップします。 sedがそのチャンクを処理している間、catは別のチャンクを読み取り、それを標準出力に書き込んで、sedが次に処理できるようにします。

言い換えると、catコマンドを追加することで必要となる追加の作業は、追加のcatプロセスを生成する追加の作業だけでなく、バ​​イトの読み取りと書き込みの追加の作業でもあります。 1回ではなく2回ファイルします。さて、実際に言えば、最近のシステムでは、大きな違いはありません。システムが数マイクロ秒の不要な作業を行う可能性があります。しかし、配布する予定のスクリプトの場合、潜在的に能力不足のマシンでスクリプトを使用する可能性がある場合は、数マイクロ秒で多くの反復を合計できます。

9
godlygeek