>&- Unix / Linux端末では何をすべきですか?

>&- Unix / Linux端末では何をすべきですか?

私はUnixのコマンドラインを知りません。私が見つけたこの回答標準出力に出力せずにコマンドを使用するには、tee次のように「標準出力オフ」を渡します>&-

echo 'hello world' | tee aa bb cc >&-

たくさん研究して見つけました。その他の投稿演算子の機能についてお問い合わせください。残念ながら、詳細な回答が見つかりません。

私が知っているのは閉鎖されたstdoutだけですが、それが正確に何を意味するのか、なぜ誰かがそうしようとするのかはわかりません。これが役に立つかもしれない他のシナリオが何であるかを知りたいです。

その演算子の内部操作についてさらに学ぶことができるリソースはありますか?

ベストアンサー1

引用するsh言語のPOSIX仕様:

2.7.6 出力ファイル記述子のコピー

リダイレクト演算子:

[n]>&word

出力ファイル記述子は他の出力ファイル記述子からコピーする必要があります。または1つ閉じる。単語が1つ以上の数値として評価されると、nまたは標準出力(nが指定されていない場合)で表されるファイルディスクリプタは、単語の数字がForを使用して開かれたファイルを表していない場合、単語として表示されるファイルディスクリプタのコピーになります。出力ファイル記述子でリダイレクトエラーが発生します。シェルエラーの結果を参照してください。単語が「-」と評価されると、ファイル記述子nまたは標準出力(nが指定されていない場合)が閉じます。開いていないファイル記述子を閉じようとすることは、エラーと見なすべきではありません。単語が異なると評価された場合、アクションは指定されません。

(強調)。

stdoutのファイル記述子である1の略語も同じ>&-です。1>&-

だから:

cmd >&-

シェルはclose(1)後で実行されるプロセスでこれを行いますcmd。したがってcmd、fd 0と2は起動時に開かれます(それぞれstdinとstderrなので、stdoutは通常、慣例に従ってコマンドがデフォルトで入力を許可し、デフォルトで間違った場所を送信すると予想するため、常に何かにあります)。 )、しかしFD 1はオフになっています。ファイルディスクリプタ3以上も閉じることができます。

つまり、cmdファイルが開かれると(たとえばopen("some-file", O_WRONLY, 0600))、最初の無料ファイル記述子で開き、fdは1になります。これはsome-file後で標準出力の位置になることを意味します。たとえば、printf("Please enter your name: ")後で発生した場合some-file

これは(数十年間)setuid実行可能ファイルを悪用する方法でした。

たとえば、chshsetuid 実行可能ファイルを/etc/passwd編集して、ユーザーの要求に応じてユーザーのログインシェルを変更できます。

そして:

chsh >&-

chsh/etc/passwdfd 1でaを開き、そこにいるユーザーに送信するメッセージを書くこともできます。

この問題を認識した後、ソフトウェアは起動時にfd 0、1、または2が閉じられていることを確認し、閉じている場合は開いて/dev/nullそれを防止し始めました。

私はこれが少なくともsetuid実行可能ファイルまたは他の機密性の高いコンテキストで実行されていることを検出するときにGNU libc(GNUシステムのすべての実行可能ファイルで使用される)が実行する操作であることを覚えているようですが、今は確認できません。 I 彼らはそれを誤って覚えたか、行動を変えました。

とにかくtee今GNUソースコードを見ると、書き込み用にファイルを開くときに次のように使用します。fopen_safer()gnulibのバリアント(GNU libcではない)fopen()、fd fopen()<= 2を使用している場合は、2よりも高いfdに移動します。

したがって、少なくともtee aa bb cc >&-この実装を使用すると、2(おそらく3)以上の最初のfdが開き、次のfdが開くように進み、1は閉じたままになるため、次のことがわかります。teeaabb

$ echo test | tee aa bb cc >&-
tee: 'standard output': Bad file descriptor

teefd 1(stdout)が閉じている間に書き込めないときにエラーを報告します。

busyboxの場合はgnulibのものをtee使わず、fopen_safer()

$ echo test | busybox tee aa bb cc >&-
$ cat aa
test
test

aa実際にはfd 1にあり、これがtestそこに2回記録される理由を説明します。一度はstdout(fd 1)に書き込まれたため、もう1つは開かれたfd aa(またfd 1)に書き込まれたからです。

teestdout(または他のコマンド)を削除するには、次のことが必要であることを明確にしてください。いいえ閉じて/ dev / nullにリダイレクトします。

echo test | tee aa bb cc > /dev/null

しかし、ここでは捨てるのではなく、次のようにすることができます。

echo test | tee aa bb > cc
echo test | tee aa bb cc >&-

tee前述のように、保護対策としてstdoutが閉じられたことを検出して/dev/nullで再度開く実装の場合にのみ、これはGNUteeやbusyboxの場合ではありませんtee(少なくとも現在のバージョンのGNUライブラリ)。

stdout(またはstdinまたはstderr)をオフにするいくつかの理由は次のとおりです。

  • 実行時に権限を向上させますが、これらの病理学的ケースでは正しく機能しないsetuid / setgidまたはより一般的なソフトウェアを悪用します。

  • ソフトウェアをテストして、これらの条件で正しく機能していることを確認してください。

  • in では、zsh出力cmd1 > file | cmd2をパイプとパイプのcmd1両方に送信します(内部的に実行され、より柔軟であることを除いて、ingと似ています)。filecmd2cmd1 | tee file | cmd2tee

    cmd1stderrをに送信してstdoutをに送信しようとすると、stderrはに送信され、stdoutはに送信cmd2 できません。filecmd1 2>&1 > file | cmd2cmd2filecmd2

    tee以下を実行して無効にできます。

    cmd1 2>&1 >&- > file | cmd2
    

    次のようにすることもできます。

    { cmd1 2>&1 > file; } | cmd2
    

    または

    cmd1 > file 2> >(cmd2)
    

あるいは、1<&-その問題との間>&-の唯一の違いは、指定されてい<&-ない場合に機能するfdです(それぞれ1と0)。彼らはすべて1つだけを作りましたclose(fd)

おすすめ記事