Esse 255descritor de arquivo é um identificador aberto para o controle tty e é usado apenas quando bashé executado no modo interativo.
Ele permite que você redirecione o stderrno 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 ksh93que está simplesmente usando o descritor de arquivo 2 como referência para o terminal de controle, o sleepprocesso 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 sleepcomo o primeiro plano no terminal tcsetgrp(), pois o descritor de arquivo 2 não aponta mais para o terminal.
Isso não é bashespecífico, também é usado em dashe 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 bashestã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.
bashestá usando um número tão grande para permitir que fds maiores do 9que 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_ttyvariá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 stderrestiver conectada a um terminal) ou abrindo diretamente /dev/ttye, 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_ttyainda 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]etpgrpno 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_ttyestão todos configurados para fechar em execução, para que não sejam vazados para comandos.