ファイル記述子(またはファイルハンドラー)はファイルIOテクニックLinuxシステムでは。
また、各プロセスには3つの標準ストリーム(つまり、stdin、stdout、stderr)があり、それらは0〜3の記述子を持つファイルで表されます。
しかし、私がlsof -p <pid>
で調べたすべてのプロセスには、読み取り権限を持つ追加のファイル記述子255
があることに気づきました。
this answer から、この機能はBash Shellに固有であることがわかりましたが、回答と参照されたソースの両方がこれについて実際に説明していませんファイル記述子用です。
私の質問:
あなたの質問の最後の部分について:
man bash
:
シェルが内部で使用するファイル記述子と競合する可能性があるため、9より大きいファイル記述子を使用するリダイレクトは注意して使用する必要があります。
そのため、その番号を使用して新しいfdを作成する場合、答えはノーです。
次のように使用する場合:「そのfdに書き込む」:
$ echo hello >/dev/fd/255"
またはそれから読むには:
$ read a </dev/fd/255
abc
$ echo "$a"
abc
答えはイエスです。
しかし、おそらく、(シェルとは関係なく)/dev/tty
_tty
にアクセスします。
ケースfd 1(/dev/stdout
)およびfd 0(/dev/stdin
)ブロックされます。
詳細 。
他のシェルは異なる番号を使用する場合があります(zshの10など)
$ zsh
mail% ls -l /proc/self/fd /proc/$$/fd/* &
[1] 3345
mail% lrwx------ 1 isaac isaac 64 Oct 14 09:46 /proc/3250/fd/0 -> /dev/pts/2
lrwx------ 1 isaac isaac 64 Oct 14 09:50 /proc/3250/fd/1 -> /dev/pts/2
lrwx------ 1 isaac isaac 64 Oct 14 09:50 /proc/3250/fd/10 -> /dev/pts/2
lrwx------ 1 isaac isaac 64 Oct 14 09:50 /proc/3250/fd/2 -> /dev/pts/2
/proc/self/fd:
total 0
lrwx------ 1 isaac isaac 64 Oct 14 09:50 0 -> /dev/pts/2
lrwx------ 1 isaac isaac 64 Oct 14 09:50 1 -> /dev/pts/2
lrwx------ 1 isaac isaac 64 Oct 14 09:50 2 -> /dev/pts/2
lr-x------ 1 isaac isaac 64 Oct 14 09:50 3 -> /proc/3345/fd
[1] + done ls -l /proc/self/fd /proc/$$/fd/*
mail%
送信元 メールリスト :
Fd 255は、ttyへの接続として内部的に使用されるため、execを使用してfdを再配置することを妨げません。同じ理由で、bashはプロセス置換 `<(foo) 'を処理するときに高いfdsも割り当てます。
アンドレアスシュワブ
その_255
_ファイル記述子は、制御ttyへのオープンハンドルであり、bash
がインタラクティブモードで実行されている場合にのみ使用されます。
メインシェルでstderr
をリダイレクトしながら、ジョブ制御を機能させます(つまり、^ Cでプロセスを強制終了したり、^ Zでプロセスを中断したりできます)。
例:
_$ exec 2> >(tee /tmp/err); ls /nosuchfile; sleep 1000
_
制御端末への参照としてファイル記述子2を単に使用している_ksh93
_のようなシェルでそれを試すと、sleep
プロセスは^ Cおよび^ Zの影響を受けなくなり、別のウィンドウ/セッションから強制終了されます。これは、ファイル記述子2がもはやターミナルを指していないため、シェルがsleep
のプロセスグループをtcsetgrp()
を使用してターミナルのフォアグラウンドグループとして設定できないためです。
これはbash
固有ではなく、dash
およびzsh
でも使用されます。記述子がそれほど高く移動されない(通常は10)ことだけです。
zsh
もそのfdを使用してプロンプトとユーザー入力をエコーするので、次のように単純に機能します。
_$ exec 2>/tmp/err
$
_
スクリプトを読み込んでパイプを設定するときにbash
が使用しているファイルハンドルとは何の関係もありません(同じ関数--move_to_high_fd()
でも邪魔になりません)。他の回答やコメントで提案されたように。
bash
は、_9
_より大きいfdsをシェル内リダイレクトで使用できるようにするために、このような大きな数を使用しています(例:_exec 87<filename
_);他のシェルではサポートされていません。
そのファイルハンドルは自分で使用できますが、_... < /dev/tty
_を使用して、すべてのコマンドでsame制御端末にハンドルを取得できるため、そうすることにはほとんど意味がありません。
bashのソースコード分析:
bash
では、制御端末のファイル記述子が_Shell_tty
_変数に格納されます。シェルがインタラクティブである場合、その変数はjobs.c:initialize_job_control()
でstderr
から複製することで(起動時または失敗したexecの後で)初期化されます(stderr
が端末)または_/dev/tty
_を直接開いて、general.c:move_to_high_fd()
を使用して再度高いfdに複製します。
_int
initialize_job_control (force)
int force;
{
...
if (interactive == 0 && force == 0)
{
...
}
else
{
Shell_tty = -1;
/* If forced_interactive is set, we skip the normal check that stderr
is attached to a tty, so we need to check here. If it's not, we
need to see whether we have a controlling tty by opening /dev/tty,
since trying to use job control tty pgrp manipulations on a non-tty
is going to fail. */
if (forced_interactive && isatty (fileno (stderr)) == 0)
Shell_tty = open ("/dev/tty", O_RDWR|O_NONBLOCK);
/* Get our controlling terminal. If job_control is set, or
interactive is set, then this is an interactive Shell no
matter where fd 2 is directed. */
if (Shell_tty == -1)
Shell_tty = dup (fileno (stderr)); /* fd 2 */
if (Shell_tty != -1)
Shell_tty = move_to_high_fd (Shell_tty, 1, -1);
...
}
_
_Shell_tty
_がまだ制御ttyでない場合は、次のように作成されます。
_ /* If (and only if) we just set our process group to our pid,
thereby becoming a process group leader, and the terminal
is not in the same process group as our (new) process group,
then set the terminal's process group to our (new) process
group. If that fails, set our process group back to what it
was originally (so we can still read from the terminal) and
turn off job control. */
if (Shell_pgrp != original_pgrp && Shell_pgrp != terminal_pgrp)
{
if (give_terminal_to (Shell_pgrp, 0) < 0)
_
_Shell_tty
_は次に使用されます
フォアグラウンドプロセスグループを取得および設定するには、jobs.c:maybe_give_terminal_to()
、jobs.c:set_job_control()
およびjobs.c:give_terminal_to()
の_tc[sg]etpgrp
_を使用します。
termios(3)
およびjobs.c:get_tty_state()
のjobs.c:set_tty_state()
パラメータを取得および設定します
ioctl(TIOCGWINSZ)
のlib/sh/winsize.c:get_new_window_size()
を使用して、ターミナルウィンドウのサイズを取得します。
move_to_high_fd()
は通常、bash
によって使用されるすべての一時ファイル記述子(スクリプトファイル、パイプなど)とともに使用されます。そのため、Google検索で目立つほとんどのコメントで混乱が生じます。
_Shell_tty
_を含む、bash
によって内部的に使用されるファイル記述子はすべて、exec-on-execに設定されているため、コマンドにリークされることはありません。