web-dev-qa-db-ja.com

シェルは、不要な終了コマンドを最適化することを許可されていますか?

cat hugeregularfile.txt > /dev/nullなど、シェルが終了することがわかっているおそらく役に立たない(または部分的に役に立たない)コマンドを実行するように求められた場合、そのコマンドの実行をスキップできます(またはより安価な同等物を実行します、たとえば、touch -a hugeregularfile.txt)?

より一般的には、シェルはCコンパイラに似ていますが、外部から観察可能な動作が as-ifである限り、ソースコードで変換を実行できます抽象マシンが評価しましたか?

[〜#〜]編集[〜#〜]

Nota Bene:最初に提起された私の質問には、シェルがこれらの最適化を行うことが許可されているかどうか、またはそれらを実行できる実装が存在するかどうかではなく、タイトルがありました。どちらも大歓迎ですが、私は実践よりも理論に興味があります。

いいえ、それは悪い考えです。

cat hugeregularfile.txt > /dev/nulltouch -a hugeregularfile.txtは同じではありません。 catは、出力を/dev/nullにリダイレクトしても、ファイル全体を読み取ります。そして、ファイル全体を読み取ることは、まさにあなたが望むものであるかもしれません。たとえば、後の読み取りが大幅に速くなるようにキャッシュするためです。シェルはあなたの意図を知ることができません。

同様に、Cコンパイラは、読み取ったものを見ていない場合でも、ファイルの読み取りを最適化することはありません。

26
scai

いいえ、/dev/nullは単なる名前であり、「通常」はデータシンク以外のデバイスやファイルに使用できます。

したがって、シェル(または他のプログラム)は、名前に基づいて、書き込み先のfileがデータに対して「実際に」何かを行っているかどうかを知りません。 AFAIKには、シェルプログラムが実行できるシステムコールもありません。ファイル記述子は実際には何もしていません。

シェルには、Cコンパイラがソースコードの一部について持っている全体的な概要がないため、Cプログラムでのコードの最適化との比較は機能しません。シェルは/dev/nullを十分に理解していないため、例を最適化できません。Cコンパイラは、動的にリンクする関数呼び出しのコードを十分に知らないため、呼び出しを実行できません。

20
Anthon

それは実行中のコマンドを最適化しません(そして、なぜそうすべきでないかを伝える多くの良い答えをすでに受け取っています)が、場合によってはフォーク、パイプ/ソケットペア、読み取りを最適化するかもしれません。それが行うかもしれない種類の最適化:

  • 最近のほとんどのシェルでは、trapsが設定されていない限り、スクリプトの最後のコマンドは通常シェルのプロセスで実行されます。たとえば_sh -c ls_の場合、ほとんどのsh実装(bashmkshkshzshyashash)の一部のバージョンは、lsを実行するプロセスをフォークしません。
  • _ksh93_では、コマンド置換は外部コマンドが呼び出されるまでパイプまたはフォークプロセスを作成しません(たとえば、$(echo foo)はパイプ/ソケットペアまたはフォークなしでfooに展開されます)。
  • 一部のシェル(read、AT&T bash)のkshビルトインは、stdinがシーク可能であることを検出した場合、シングルバイトの読み取りを行いません(この場合、それらは大きくなります)読んで、彼らが読むつもりであるものの終わりまでさかのぼります。
14

cat hugeregularfile.txt > /dev/nullを見ると、シェルはそのアクションが役に立たないと信じることはできません。catはシェルの一部ではなく、理論上も実際にも何でも実行できます。

たとえば、ユーザーが実行可能ファイルの名前をrmからcatに変更した場合、その行は突然、外部から観察可能な動作、つまりファイルの削除を実行します。

ユーザーは、無限ループに入るバージョンのcatをコンパイルした可能性があります。そのため、シェルはそれが「終了することがわかっている」とは想定できません。

意図したとおりに機能するバージョンのcatを誰かがインストールした可能性がありますが、ルートキットが適切な権限で実行された場合、ルートキットをインストールするという副次的な影響があります。これも、シェルが正しく実行するはずです。

7
Peteris