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


27

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

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

編集

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


いいえ、シェルは最新のコンパイラほどスマートではありません。実際、かなり馬鹿げています。無駄なコードは最適化されません。
devnull

12
ユーザーの意図が何かを推測することは、シェルがすべきことではありません。ユーザーはそのコマンドを使用してほとんど何でもしようとする可能性がありますが、それが可能であっても、それを最適化するのは間違っています。
クリスダウン14年

1
ファイルがデバイスである場合、catそれを変更すると大きな違いが生じると言っても関係ありません。シェルはファイルがデバイスであることを知ることができますが、信頼できる必要はありません。
yo

3
@StephaneChazelas Cコンパイラは、コンパイルされたプログラムを最適化するために「誰かに許可を求める」必要はありません。あるとして、もしそうするためにそれらを許可するC規格のルールが。POSIX標準は、少なくとも1つのシェル(pubs.opengroup.org/onlinepubs/009695399/utilities/…)と他の多くのユーティリティ(pubs.opengroup.org/onlinepubs/009604499/utilities/wc.html for wc、 例えば)。しかし、私の知る限り、POSIXはシェルの最適化の位置を占めていません。それともそうですか?
Iwillnotexist Idonotexist

2
最適化により、機能に影響を与えることなくショートカットを使用してパフォーマンスが向上します。機能が保証されている限り、POSIXのオブジェクト化は見えません。ただし、最適化の提案はcatの仕様に違反します。POSIX仕様には、によって行われる最適化のタイプに対応する特定の文言がありますksh。彼らは言っていないと同じように、別のプロセスが、サブシェル環境はフォーク節約最適化を可能にするために。
ステファンシャゼル14年

回答:


26

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

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

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


2
@Iwillnotexist:すべての有用なコマンド(ほぼ間違いなくtrueとを除くfalse)には潜在的な副作用があり、副作用はほとんど常にコマンドを呼び出すポイントです。シェルはcat、停止問題を解決しない限り、これらの副作用を事前に知ることができませんでした(などの外部プログラムの場合)。したがって、当然のことながら試行されず、あなたが言ったことを意味していると仮定します。
cHao

5
@IwillnotexistIdonotexistいいえ、シェルはこれから起こることすべてを見ることはできません。それについては全く知りませんcat。実際、catハードドライブのフォーマットからインターネットのダウンロードまで何でもできます。
scai

5
「Unixは、ユーザーが愚かなことをするのを防ぐようには設計されていません。-
ダググウィン

7
@cHaoそして偶数truefalse設定$?
カイルストランド14年

3
上記の@scaiが指摘したように、実行可能ファイルは言語キーワードのようなものではありませ。典型的な意味cat/dev/null持っていますが、そのように動作することは保証されていませ。予想される動作への変更を保証せずに最適化を実行するには、最適化には、シェル自体に実装された構造のみが含まれ、実行環境で見つかったものは含まれません...名前がどれほど直感的に見えても関係ありません。
andybuckley

20

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

そのため、シェル(または他のプログラム)は、名前に基づいて、書き込み先のファイルがデータに対して「実際に」何かを実行しているかどうかを知りません。また、たとえば、ファイル記述子が実際には何もしていないことを判断するために、シェルプログラムが実行できるシステム呼び出しはありません。

Cプログラムのアウェイコードの最適化との比較は機能しません。シェルには、Cコンパイラがソースコードに対して持つ全体的な概要がないためです。/dev/nullCコンパイラーが動的にリンクする関数呼び出しのコードを十分に知らないため、呼び出しを行わないように、シェルは例を最適化するほど十分に知りません。


4
判明したように、ksh93は/dev/null時々特別に扱います。/dev/nullたとえばecho foo >/dev/null、stdoutが指定されている組み込みは、に書き込みが行われることはありません/dev/null。非組み込みコマンド(などcat file >/dev/null)を呼び出している場合、特別なことは行いません。
マークPlotnick 14年

実際のところ、cat他の何かかもしれません。実際には他のもの。
オリオン14年

3
実際には/dev/null非常に少数の一つである標準化された経路とともに、/dev/tty/dev/console/tmp/dev/および/
ジル「SO-悪であるのをやめる」14年

2
@MarkPlotnick cat 、実際に ksh93 ビルトインです(/opt/ast/bin前に/bin(またはcat利用可能な場所がある場合)を置かない限り有効になりません$PATH)。そして、はい、cat file > /dev/nullその組み込みではreadのコンテンツを行いますがfile、/ dev / nullに書き込みませ(ただし、開いてfstatsします)。
ステファンシャゼル14年

14

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

  • 最近のほとんどのシェルでは、スクリプトの最後のコマンドは、いくつかtrapのが設定されていない限り、通常シェルのプロセスで実行されます。で、例えばsh -c ls、ほとんどの sh実装(bashmkshkshzshyash、いくつかのバージョンではash)を実行するプロセスをフォークしないであろうls
  • ではksh93、コマンド置換は、外部コマンドが呼び出されるまでプロセスをパイプまたはフォークしません($(echo foo)たとえばfoo、パイプ/ソケットペアまたはフォークなしで展開します)。
  • readいくつかのシェルの組み込み(bash、AT&T ksh)は、stdinがシーク可能であることを検出した場合、シングルバイトの読み取りを行いません(この場合、大きな読み取りを行い、読み取ることを意図した最後までシークします)。

私はこの答えが好きですが、これが元の理由なのか、情報が何らかの参照から取得されたものなのかは不明です(
詳しく調べ

3
@yoniYalovitsky、それが元の理由です。ksh93は、最適化の最前線にあるシェルであり、その目的はのようなプログラミング言語に匹敵するものと見なされていましたperl。したがって、詳細kshについては、ドキュメント、コード(幸運)、およびメーリングリストを参照してください。
ステファンシャゼル14年

1
@HenkLangeveldは、はい、あなたがいることを確認することができsh -c 'ps -p "$$"'たあなたを与えるだろうpsし、ないshものとsh実装、またはstraceの/トラス/ TUSC ...と
ステファンChazelas

1
ksh -c 'ps; ps'とbash -c 'ps; ps' の違いは興味深いです。Ksh93の最適化はさらに進んでいます。
ヘンクランゲベルド

1
@HenkLangeveldは、kshここで話している実装に依存します。mkshのように動作しbashます。その動作は主にのようなものを最適化することを意図していsystem("some command")ます。(一部のシェルでは)シグナルによって終了したプロセスの終了ステータスに関しては、その最適化の副作用があることに注意してください。ksh93以前は、トラップが設定されていても最適化を行っていたというバグがありました。
ステファンシャゼル

7

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

たとえば、ユーザーが実行可能ファイルを名前を変更したことrmcat、ファイルを削除する、すなわち、外部から観察可能な行動をし、突然ラインを実行します。

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

誰かがcat意図したとおりに動作するバージョンをインストールした可能性がありますが、適切な権限で実行された場合にルートキットをインストールするという余分な副作用があります。


2
実際、ビルトインにすることmkshで実際に最適化V=$(cat file)します。そのため、シェルはそれを最適化するかもしれませんが、それをただに変換することはできませんtouch -a
スティーブシュネップ14年

1
@SteveSchneppは、cat あるで組み込みmkshが、システムへの組み込みリゾートがいcatた場合にGNUと理由でいずれかのオプション、渡されcatmksh -c 'cat /dev/null --help'同じ結果が得られていないがbash -c 'cat /dev/null --help'、しかし、mksh -c 'cat --help /dev/null'あなたと同じを与えないbash -c 'cat --help /dev/null'よう(mkshパースオプションPOSIX組み込み猫GNU catはそれらをGNU方式で解析します)。
ステファンシャゼル14年

bashとksh93では、V=$(cat file)で最適化できますV=$(< file)。これは組み込みなしで物事をスピードアップしcatます。
ヘンクランゲベルド
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.