Этот 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]etpgrpin 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, поэтому они не будут передаваться командам.