わかりました。ファイル記述子(またはファイルハンドラ)はいファイルIOテクノロジLinuxシステムで。
また、すべてのプロセスには、0から3までの記述子を持つファイルで表される3つの標準ストリーム(つまりstdin、stdout、およびstderr)があることもわかっています。
しかし、私が確認したすべてのプロセスには、lsof -p <pid>
読み取り権限を持つ追加のファイル記述子があることがわかりました。255
~からこの回答、私はこの機能が次に特定であることを学びました。バッシュシェルただし、答えや引用されたソースのいずれも、実際にこのファイル記述子が使用される用途を説明していません。
私の質問:
- 255 ファイル記述子の用途は?
- 私のBashスクリプトでこれを使用できますか?それとも手動で使用/操作してはならない内部作業メカニズムですか?
答え1
質問の最後の部分は次のとおりです。
使えますか?
からman bash
:
9より大きいファイル記述子を使用するリダイレクトは、シェルで内部的に使用されるファイル記述子と競合する可能性があるため、慎重に使用する必要があります。
したがって、その番号で新しいファイル記述子を生成するという意味であれば、答えは「いいえ」です。
asを使用して「対応するfdに書き込む」を意味する場合:
$ echo hello >/dev/fd/255"
または、以下でお読みください。
$ read a </dev/fd/255
abc
$ echo "$a"
abc
答えは「はい」です。
しかし、おそらく/dev/tty
それを使用してtty
。
ファイル記述子255は何に使用されますか?
/dev/stdout
fd 1()とfd 0(/dev/stdin
)がブロックされている場合は、ttyへの代替接続として機能します。
詳しくは。
異なるシェルでは異なる数字を使用できます(例: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)"を処理するときに高いfdを割り当てます。
アンドレアス・シュワップ
答え2
このファイル記述子は制御 tty のオープンハンドルであり、255
対話モードで実行されている場合にのみ使用されます。bash
これにより、ジョブ制御の実行を許可しながらメインシェルからリダイレクトすることができますstderr
(つまり、^Cでプロセスを終了し、^Zでプロセスを中断する機能など)。
例:
$ exec 2> >(tee /tmp/err); ls /nosuchfile; sleep 1000
ksh93
単にファイル記述子2を制御端末への参照として使用するこのようなシェルでこれを試みると、sleep
プロセスは^ Cと^ Zの影響を受けず、別のウィンドウ/セッションで終了する必要があります。これは、ファイルディスクリプタ2が端末を指していないため、シェルがそれを使用してプロセスグループを端末sleep
の前景プロセスグループに設定できないためです。tcsetgrp()
これは具体的ではなく、合計bash
にも当てはまります。ただ記述子がそんなに高く移動していないだけです(通常10)。dash
zsh
zsh
このfdはプロンプトとユーザー入力をエコーするためにも使用されます。
$ exec 2>/tmp/err
$
他の回答やコメントで提案したように、スクリプトを読み込んでパイプを設定するときに使用されるファイルハンドルとは関係ありませんbash
(このパイプは同じ機能を使用してコピーされます - )。move_to_high_fd()
bash
このように大きな数値を使用することは、fdが(たとえば)シェル内のリダイレクト9
に使用される値よりも大きくなるようにすることです。他のシェルはこれをサポートしていません。exec 87<filename
ファイルハンドルを直接使用することもできますが、ファイルハンドルを取得できるため、そうすることはあまり意味がありません。同じ... < /dev/tty
以下を使用して、すべてのコマンドで端末を制御します。
bashソースコードの分析:
では、bash
制御端末のファイル記述子がshell_tty
変数に格納されます。シェルが対話型の場合、変数は端末にjobs.c:initialize_job_control()
接続されているstderr
場合はstderr
コピーまたは直接開いて(起動時または実行失敗後)初期化されます/dev/tty
。その後、親fdにコピーし直してくださいgeneral.c:move_to_high_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
その後、使用
tc[sg]etpgrp
injobs.c:maybe_give_terminal_to()
とを使用してjobs.c:set_job_control()
フォアグラウンドプロセスグループを取得して設定します。jobs.c:give_terminal_to()
termios(3)
とでパラメータを取得して設定するjobs.c:get_tty_state()
jobs.c:set_tty_state()
ioctl(TIOCGWINSZ)
端末ウィンドウのサイズを取得するには、inを使用しますlib/sh/winsize.c:get_new_window_size()
。
move_to_high_fd()
一般的に使用されるすべての一時ファイル記述子(スクリプトファイル、パイプなど)と組み合わせて使用されるため、bash
Google検索で強調されたほとんどのコメントで混乱が発生します。
内部で使用されるファイル記述子はbash
実行shell_tty
時に閉じるように設定され、コマンドに漏れません。