Esse 255
descritor de arquivo é um identificador aberto para o controle tty e é usado apenas quando bash
é executado no modo interativo.
Ele permite que você redirecione o stderr
no shell principal, enquanto ainda permite que o controle da tarefa funcione (por exemplo, seja capaz de matar processos com ^ C, interrompê-los com ^ Z, etc).
Exemplo:
$ exec 2> >(tee /tmp/err); ls /nosuchfile; sleep 1000
Se você tentar isso em um shell como o ksh93
que está simplesmente usando o descritor de arquivo 2 como referência para o terminal de controle, o sleep
processo ficará imune a ^ C e ^ Z e terá que ser eliminado de outra janela / sessão. Isso ocorre porque o shell não poderá definir o grupo de processos sleep
como o primeiro plano no terminal tcsetgrp()
, pois o descritor de arquivo 2 não aponta mais para o terminal.
Isso não é bash
específico, também é usado em dash
e zsh
, apenas que o descritor não seja movido tão alto (geralmente é 10).
zsh
também usará esse fd para fazer eco das solicitações e da entrada do usuário; portanto, simplesmente o seguinte funcionará:
$ exec 2>/tmp/err
$
Não tem nada a ver com o que os manipuladores de arquivos bash
estão usando ao ler scripts e configurar pipes (que também são desviados com a mesma função - move_to_high_fd()
), como foi sugerido em outras respostas e comentários.
bash
está usando um número tão grande para permitir que fds maiores do 9
que sejam usados com redirecionamentos no shell (por exemplo exec 87<filename
); isso não é suportado em outras conchas.
Você pode usar esse arquivo sozinho, mas há pouco sentido em fazê-lo, porque você pode obter um identificador para o mesmo terminal de controle em qualquer comando com ... < /dev/tty
.
Análise do código fonte do bash :
Em bash
, o descritor de arquivo do terminal de controle é armazenado na shell_tty
variável Se o shell for interativo, essa variável será inicializada (na inicialização ou após uma falha no exec) jobs.c:initialize_job_control()
, duplicando-a stderr
(se stderr
estiver conectada a um terminal) ou abrindo diretamente /dev/tty
e, em seguida, duplicando novamente para um valor de fd mais alto com 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);
...
}
Se shell_tty
ainda não é o tty de controle, é feito o seguinte:
/* 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
é então usado para
obter e definir o grupo processo em primeiro plano com tc[sg]etpgrp
no jobs.c:maybe_give_terminal_to()
, jobs.c:set_job_control()
ejobs.c:give_terminal_to()
obter e definir os termios(3)
parâmetros jobs.c:get_tty_state()
ejobs.c:set_tty_state()
obtenha o tamanho da janela do terminal com ioctl(TIOCGWINSZ)
in lib/sh/winsize.c:get_new_window_size()
.
move_to_high_fd()
geralmente é usado com todos os descritores de arquivos temporários usados por bash
(arquivos de script, pipes, etc.), daí a confusão na maioria dos comentários que aparecem com destaque nas pesquisas do Google.
Os descritores de arquivo usados internamente por bash
, inclusive, shell_tty
estão todos configurados para fechar em execução, para que não sejam vazados para comandos.