Quel 255
descrittore di file è un handle aperto per il tty di controllo e viene utilizzato solo quando bash
viene eseguito in modalità interattiva.
Permette di reindirizzare la stderr
shell principale, pur consentendo al controllo del lavoro di funzionare (cioè essere in grado di terminare i processi con ^ C, interromperli con ^ Z, ecc.).
Esempio:
$ exec 2> >(tee /tmp/err); ls /nosuchfile; sleep 1000
Se lo provi in una shell come ksh93
, che sta semplicemente usando il descrittore di file 2 come riferimento al terminale di controllo, il sleep
processo diventerà immune da ^ C e ^ Z e dovrà essere ucciso da un'altra finestra / sessione. Questo perché la shell non sarà in grado di impostare il gruppo di processo sleep
come primo piano nel terminale con tcsetgrp()
, poiché il descrittore di file 2 non punta più al terminale.
Questo non è bash
specifico, è anche usato in dash
e zsh
, solo che il descrittore non è spostato così in alto (di solito è 10).
zsh
userà anche quel fd per riecheggiare i prompt e l'input dell'utente, quindi semplicemente funzionerà quanto segue:
$ exec 2>/tmp/err
$
Non ha nulla a che fare con gli handle di file bash
utilizzati durante la lettura di script e l'impostazione di pipe (che sono anche duplicati con la stessa funzione - move_to_high_fd()
), come è stato suggerito in altre risposte e commenti.
bash
sta usando un numero così grande per consentire a fds più grandi di quelli 9
da utilizzare con reindirizzamenti in-shell (ad es. exec 87<filename
); non è supportato in altre shell.
Puoi usare quel file handle te stesso, ma non ha molto senso farlo, perché puoi ottenere un handle allo stesso terminale di controllo in qualsiasi comando con ... < /dev/tty
.
Analisi del codice sorgente di bash :
In bash
, il descrittore di file del terminale di controllo è memorizzato nella shell_tty
variabile. Se la shell è interattiva, quella variabile viene inizializzata (all'avvio o dopo un exec fallito) jobs.c:initialize_job_control()
duplicandola da stderr
(se stderr
è collegata a un terminale) o aprendola direttamente /dev/tty
, e quindi viene nuovamente duplicata su una fd superiore con 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
non è già il tty di controllo, allora è fatto così:
/* 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
viene quindi utilizzato
ottenere e impostare il gruppo di processi in primo piano con tc[sg]etpgrp
in jobs.c:maybe_give_terminal_to()
, jobs.c:set_job_control()
ejobs.c:give_terminal_to()
ottenere e impostare i termios(3)
parametri in jobs.c:get_tty_state()
ejobs.c:set_tty_state()
ottenere le dimensioni della finestra del terminale con ioctl(TIOCGWINSZ)
in lib/sh/winsize.c:get_new_window_size()
.
move_to_high_fd()
viene generalmente utilizzato con tutti i descrittori di file temporanei utilizzati da bash
(file di script, pipe, ecc.), quindi la confusione nella maggior parte dei commenti che appaiono in primo piano nelle ricerche su Google.
I descrittori di file utilizzati internamente da bash
, incluso shell_tty
sono tutti impostati su close-on-exec, quindi non saranno divulgati ai comandi.