Esse descritor de arquivo 255
é 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 de trabalho funcione (isto é, 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 ksh93
, que está simplesmente usando o descritor de arquivos 2 como uma referência ao terminal de controle, o processo sleep
se tornará imune a ^ C e ^ Z, e terá que ser morto de outra janela / sessão. Isso porque o shell não poderá definir o grupo de processos de sleep
como o primeiro plano no terminal com tcsetgrp()
, já que o descritor de arquivo 2 não aponta mais para o terminal.
Isso não é bash
específico, ele também é usado em dash
e zsh
, apenas que o descritor não é movido tão alto (geralmente é 10).
zsh
também usará o fd para fazer eco aos prompts e à entrada do usuário, portanto, simplesmente o seguinte funcionará:
$ exec 2>/tmp/err
$
Não tem nada a ver com as manipulações de arquivos que bash
está usando ao ler scripts e configurar cachimbos (que também estão fora do caminho 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 que 9
sejam usadas com redirecionamentos no shell (por exemplo, exec 87<filename
); isso não é suportado em outros shells.
Você pode usar esse identificador de arquivo, mas não faz sentido fazê-lo, porque você pode obter um identificador para o terminal de controle same 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 variável shell_tty
. Se o shell for interativo, essa variável será inicializada (na inicialização ou após uma execução com falha) em jobs.c:initialize_job_control()
, copiando-a de stderr
(se stderr
estiver anexado a um terminal) ou abrindo diretamente /dev/tty
, e é então dup'ed novamente para um fd maior 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 controlador tty, então é feito assim:
/* 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
-
obtenha e defina o grupo de processos em primeiro plano com tc[sg]etpgrp
em jobs.c:maybe_give_terminal_to()
, jobs.c:set_job_control()
e jobs.c:give_terminal_to()
-
obtenha e defina os termios(3)
params em jobs.c:get_tty_state()
e jobs.c:set_tty_state()
-
obtenha o tamanho da janela do terminal com ioctl(TIOCGWINSZ)
em 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, canais, etc), daí a confusão na maioria dos comentários que aparecem proeminentemente nas pesquisas do google.
Os descritores de arquivo usados internamente por bash
, incluindo shell_tty
, estão todos configurados como close-on-exec, então eles não serão vazados para os comandos.