Ce 255
descripteur de fichier est une poignée ouverte pour le tty de contrôle et n'est utilisé que lorsqu'il bash
est exécuté en mode interactif.
Il vous permet de rediriger le stderr
dans le shell principal, tout en permettant au contrôle de travail de fonctionner (c'est-à-dire de pouvoir tuer les processus avec ^ C, les interrompre avec ^ Z, etc.).
Exemple:
$ exec 2> >(tee /tmp/err); ls /nosuchfile; sleep 1000
Si vous essayez cela dans un shell comme ksh93
, qui utilise simplement le descripteur de fichier 2 comme référence au terminal de contrôle, le sleep
processus deviendra immunisé contre ^ C et ^ Z, et devra être tué depuis une autre fenêtre / session. En effet, le shell ne pourra pas définir le groupe de processus sleep
comme premier plan dans le terminal avec tcsetgrp()
, car le descripteur de fichier 2 ne pointe plus vers le terminal.
Ce n'est pas bash
spécifique, il est également utilisé dans dash
et zsh
, seulement que le descripteur n'est pas déplacé aussi haut (il est généralement de 10).
zsh
utilisera également ce fd pour faire écho aux invites et aux entrées utilisateur, donc simplement ce qui suit fonctionnera:
$ exec 2>/tmp/err
$
Cela n'a rien à voir avec les poignées de fichier bash
utilisées lors de la lecture de scripts et de la configuration de canaux (qui sont également dupés avec la même fonction - move_to_high_fd()
), comme cela a été suggéré dans d'autres réponses et commentaires.
bash
utilise un si grand nombre afin de permettre à des fds plus grands que 9
d'être utilisés avec des redirections dans le shell (par exemple exec 87<filename
); ce n'est pas pris en charge dans d'autres shells.
Vous pouvez utiliser ce handle de fichier vous-même, mais cela ne sert à rien, car vous pouvez obtenir un handle vers le même terminal de contrôle dans n'importe quelle commande avec ... < /dev/tty
.
Analyse du code source de bash :
Dans bash
, le descripteur de fichier du terminal de contrôle est stocké dans la shell_tty
variable. Si le shell est interactif, cette variable est initialisée (au démarrage ou après un exec échoué) en la jobs.c:initialize_job_control()
dupant stderr
(si elle stderr
est attachée à un terminal) ou en l'ouvrant directement /dev/tty
, puis est à nouveau dupée vers un fd supérieur avec 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);
...
}
Si ce shell_tty
n'est pas déjà le tty de contrôle, alors il est fait ainsi:
/* 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
est ensuite utilisé pour
obtenir et définir le groupe de processus de premier plan avec tc[sg]etpgrp
in jobs.c:maybe_give_terminal_to()
, jobs.c:set_job_control()
etjobs.c:give_terminal_to()
obtenir et définir les termios(3)
paramètres jobs.c:get_tty_state()
etjobs.c:set_tty_state()
obtenir la taille de la fenêtre du terminal avec ioctl(TIOCGWINSZ)
in lib/sh/winsize.c:get_new_window_size()
.
move_to_high_fd()
est généralement utilisé avec tous les descripteurs de fichiers temporaires utilisés par bash
(fichiers de script, tuyaux, etc.), d'où la confusion dans la plupart des commentaires qui apparaissent en bonne place dans les recherches Google.
Les descripteurs de fichiers utilisés en interne par bash
, notamment, shell_tty
sont tous définis sur close-on-exec, de sorte qu'ils ne seront pas divulgués aux commandes.