その255
ファイル記述子は、制御ttyへのオープンハンドルであり、bash
がインタラクティブモードで実行されている場合にのみ使用されます。
stderr
メインシェルでをリダイレクトしながら、ジョブ制御を機能させます(つまり、^ Cでプロセスを強制終了したり、^ Zでプロセスを中断したりすることができます)。
例:
$ exec 2> >(tee /tmp/err); ls /nosuchfile; sleep 1000
ksh93
制御ターミナルへの参照としてファイル記述子2を使用しているだけのようなシェルでそれを試すと、sleep
プロセスは^ Cおよび^ Zの影響を受けなくなり、別のウィンドウ/セッションから強制終了する必要があります。これは、ファイル記述子2がもはやターミナルを指していないため、シェルはのプロセスグループをsleep
ターミナルでフォアグラウンドのプロセスグループとして設定できないtcsetgrp()
ためです。
これはbash
特定のものではなく、dash
およびでも使用されzsh
ます。記述子がそれほど高く移動されないことだけです(通常は10です)。
zsh
また、そのfdを使用してプロンプトとユーザー入力をエコーするので、次のように機能します。
$ exec 2>/tmp/err
$
他の回答やコメントで提案されてbash
いるように、スクリプトを読み取ったりパイプを設定したりするときに使用するファイルハンドル(同じ機能で邪魔にならない-)とは関係ありませんmove_to_high_fd()
。
bash
9
シェル内リダイレクト(たとえばexec 87<filename
)で使用されるよりも大きいfdsを許可するために、このような大きな数を使用しています。他のシェルではサポートされていません。
このファイルハンドルは自分で使用できますが、を使用すると、どのコマンドでも同じ制御端末へのハンドルを取得できるので、そうする意味がほとんどありません... < /dev/tty
。
bashのソースコード分析:
ではbash
、制御端末のファイル記述子がshell_tty
変数に格納されます。シェルが対話型である場合、その変数は、中(起動時または失敗EXECの後に)初期化されるjobs.c:initialize_job_control()
からそれをdup'ingによってstderr
(場合stderr
、端末に装着される)または直接開いて/dev/tty
、その後より高いFDに再度dup'edれますと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
中jobs.c:maybe_give_terminal_to()
、jobs.c:set_job_control()
およびjobs.c:give_terminal_to()
取得および設定termios(3)
中のparamsを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検索で目立つように表示されるほとんどのコメントで混乱が生じます。
bash
を含め、内部で使用されるファイル記述子shell_tty
はすべてclose-on-execに設定されているため、コマンドにリークされることはありません。