Этот 255
файловый дескриптор является открытым дескриптором для управляющего tty и используется только при bash
запуске в интерактивном режиме.
Это позволяет вам перенаправить stderr
в основную оболочку, в то же время позволяя функционировать элементам управления заданиями (т.е. иметь возможность убивать процессы с помощью ^ C, прерывать их с помощью ^ Z и т. Д.).
Пример:
$ exec 2> >(tee /tmp/err); ls /nosuchfile; sleep 1000
Если вы попробуете это в подобной оболочке ksh93
, которая просто использует дескриптор файла 2 в качестве ссылки на управляющий терминал, sleep
процесс станет невосприимчивым к ^ C и ^ Z, и его придется убить из другого окна / сеанса. Это связано с тем, что оболочка не сможет установить группу процессов sleep
как переднюю в терминале tcsetgrp()
, поскольку файловый дескриптор 2 больше не указывает на терминал.
Это не является bash
конкретным, оно также используется dash
и zsh
, только, дескриптор не перемещается так высоко (это обычно 10).
zsh
также будет использовать этот fd для вывода подсказок и ввода данных пользователем, поэтому просто будет работать следующее:
$ exec 2>/tmp/err
$
Это не имеет ничего общего с файловыми дескрипторами bash
, которые используются при чтении скриптов и настройке каналов (которые также были дублированы с помощью той же функции - move_to_high_fd()
), как это было предложено в других ответах и комментариях.
bash
использует такое большое число для того, чтобы разрешить fds больше, чем 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
in jobs.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)
в lib/sh/winsize.c:get_new_window_size()
.
move_to_high_fd()
обычно используется со всеми дескрипторами временных файлов, используемых bash
(файлы сценариев, каналы и т. д.), поэтому путаница в большинстве комментариев, которые заметно выделяются при поиске в Google.
Файловые дескрипторы, используемые внутренне bash
, в том числе shell_tty
, установлены на close-on-exec, поэтому они не будут передаваться командам.