web-dev-qa-db-ja.com

>&-は> / dev / nullより効率的ですか?

昨日私は読んだ this SO comment これは、シェルで(少なくともbash>&-が "と同じ結果を持っている"と言う>/dev/null

そのコメントは実際にはその情報源として ABSガイド を参照しています。しかし、そのソースは、>&-構文は「ファイル記述子を閉じる」と述べています。

ファイル記述子を閉じてnullデバイスにリダイレクトするという2つのアクションが完全に同等であるかどうかは、私にはわかりません。だから私の質問は:彼らはいますか?

表面的には、記述子を閉じることはドアを閉じるようなものですが、それをnullデバイスにリダイレクトすると、リンボへのドアが開きます。ドアが閉まっているのを見つけたら何も捨てようとしないので、この2つはまったく同じようには見えませんが、ドアが開いているのを見つけたら、私はできると思います。

言い換えれば、>/dev/nullcat mybigfile >/dev/nullが実際にファイルのすべてのバイトを処理し、それを/dev/nullに書き込んでそれを忘れることを意味するのかどうか、私はいつも疑問に思っていました。一方、シェルが閉じたファイル記述子に遭遇した場合、catがまだreadすべてのバイト。

このコメント>&->/dev/null "should"は同じであると言いますが、私にはそれほど反響はありません。標準またはソースコアへの参照があるかどうかに関係なく、より信頼できる回答が欲しいです...

58
jamadagni

いいえ、確かにしないでくださいファイル記述子0、1、2を閉じたいと思います。

そうすると、アプリケーションが初めてファイルを開いたときに、ファイルはstdin/stdout/stderr ...になります。

たとえば、次の場合:

_echo text | tee file >&-
_

tee(少なくとも一部の実装、busybox 'など)が書き込み用にファイルを開くと、ファイル記述子1(stdout)で開かれます。したがって、teetextfileを2回書き込みます:

_$ echo text | strace tee file >&-
[...]
open("file", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 1
read(0, "text\n", 8193)                 = 5
write(1, "text\n", 5)                   = 5
write(1, "text\n", 5)                   = 5
read(0, "", 8193)                       = 0
exit_group(0)                           = ?
_

これはセキュリティの脆弱性を引き起こすことが知られています。例えば:

_chsh 2>&-
_

また、chsh(setuidアプリケーション)は、_/etc/passwd_にエラーメッセージを書き込む可能性があります。

一部のツールや一部のライブラリでさえ、それを防ごうとしています。たとえば、GNU teeは、書き込み用に開くファイルに0、1、2が割り当てられている場合、busybox teeが勝った場合、ファイル記述子を2の上に移動しますない.

ほとんどのツールは、stdoutに書き込めない場合(たとえば、開いていないため)、stderrにエラーメッセージを報告します(ローカリゼーションファイルを開いて解析するための追加処理を意味するユーザーの言語で...)。効率が大幅に低下し、プログラムが失敗する可能性があります。

いずれにしても、それはより効率的ではありません。プログラムは引き続きwrite()システムコールを実行します。最初に失敗したwrite()システムコールの後でプログラムがstdout/stderrへの書き込みを中止した場合にのみ、より効率的になりますが、プログラムは通常、それを行いません。通常、エラーで終了するか、試行を続けます。

71

IOW私は常に>/dev/nullcat mybigfile >/dev/nullが実際にファイルのすべてのバイトを処理し、それを/dev/nullに書き込むのでそれを忘れるのではないかといつも思っていました。

それはあなたの質問に対する完全な答えではありませんが、はい、上記はそれがどのように機能するかです。

catは、指定されたファイル、またはファイルが指定されていない場合は標準入力を読み取り、出力ファイルを出力しますその標準出力に EOF最後に指定されたファイル(標準入力を含む)、つまりitsジョブ。

>/dev/nullを追加すると、標準出力が/ dev/nullにリダイレクトされます。これは特別なファイル(デバイスノード)であり、書き込まれたものはすべて破棄されます(読み取り時にEOF)が返されます)。I/ Oリダイレクトは、シェルによって提供される機能であり、個々のアプリケーションごとに、そしてname/dev/nullに魔法のようなものはなく、ほとんどの nixのようなシステム に存在するものだけが存在します。

また、デバイスノードの特定のメカニズムはオペレーティングシステムによって異なるが、猫(GNUシステムではcoreutilsを意味する)はクロスプラットフォーム(同じソース)であることに注意することも重要です。コードは少なくともをLinuxとHurdで実行する必要があるため、特定のオペレーティングシステムカーネルに依存することはできません。さらに、/ dev/nullエイリアスを作成しても機能します(Linuxでは、これは同じメジャー/マイナーデバイス番号を持つデバイスノード)を別の名前で使用すると、同じように動作する別の場所(/ dev/zeroなど)に書き込む場合が常にあります。

catは/ dev/nullの特別なプロパティを認識せず、実際にはそもそもリダイレクトを認識していない可能性がありますが、それでも正確に実行する必要があります同じ作業:指定されたファイルを読み取り、/これらのファイルのコンテンツを標準出力に出力します。 catの標準出力がたまたまvoidになるのは、cat自体が関係するものではありません。

14
a CVn