Dieser 255
Dateideskriptor ist ein offenes Handle für das steuernde tty und wird nur verwendet, wenn er bash
im interaktiven Modus ausgeführt wird.
Sie können das stderr
in der Haupt-Shell umleiten , während die Jobsteuerung weiterhin funktioniert (dh Prozesse mit ^ C beenden, mit ^ Z unterbrechen usw.).
Beispiel:
$ exec 2> >(tee /tmp/err); ls /nosuchfile; sleep 1000
Wenn Sie dies in einer Shell wie versuchen ksh93
, die einfach den Dateideskriptor 2 als Referenz für das steuernde Terminal verwendet, wird der sleep
Prozess immun gegen ^ C und ^ Z und muss aus einem anderen Fenster / einer anderen Sitzung beendet werden. Dies liegt daran, dass die Shell die Prozessgruppe von nicht sleep
als Vordergrundgruppe im Terminal mit festlegen kann tcsetgrp()
, da der Dateideskriptor 2 nicht mehr auf das Terminal zeigt.
Dies ist nicht bash
spezifisch, es wird auch in dash
und verwendet zsh
, nur dass der Deskriptor nicht so hoch verschoben wird (normalerweise sind es 10).
zsh
wird dieses fd auch verwenden, um Eingabeaufforderungen und Benutzereingaben wiederzugeben, sodass einfach Folgendes funktioniert:
$ exec 2>/tmp/err
$
Es hat nichts mit den bash
Dateihandles zu tun, die beim Lesen von Skripten und beim Einrichten von Pipes verwendet werden (die mit derselben Funktion ebenfalls aus dem Weg geräumt werden - move_to_high_fd()
), wie dies in anderen Antworten und Kommentaren vorgeschlagen wurde.
bash
verwendet eine so große Anzahl, um zu ermöglichen, dass fds größer sind als 9
bei In-Shell-Umleitungen (z. B. exec 87<filename
); Das wird in anderen Shells nicht unterstützt.
Sie können dieses Dateihandle selbst verwenden, aber es macht wenig Sinn, dies zu tun, da Sie in jedem Befehl mit ein Handle für dasselbe steuernde Terminal erhalten können ... < /dev/tty
.
Quellcode-Analyse von Bash :
In bash
wird der Dateideskriptor des steuernden Terminals in der shell_tty
Variablen gespeichert . Wenn die Shell interaktiv ist, wird diese Variable (beim Start oder nach einer fehlgeschlagenen Ausführung) jobs.c:initialize_job_control()
durch Dup'ing von stderr
(wenn stderr
an ein Terminal angeschlossen) oder durch direktes Öffnen /dev/tty
initialisiert und dann erneut auf einen höheren fd dup'ed mit 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);
...
}
Wenn shell_tty
nicht bereits die steuernde tty ist, dann wird es so gemacht:
/* 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
ist dann daran gewöhnt
Holen und setzen Sie die Vordergrundprozessgruppe mit tc[sg]etpgrp
in jobs.c:maybe_give_terminal_to()
, jobs.c:set_job_control()
undjobs.c:give_terminal_to()
termios(3)
Holen Sie sich und setzen Sie die Parameter in jobs.c:get_tty_state()
undjobs.c:set_tty_state()
Holen Sie sich die Größe des Terminalfensters mit ioctl(TIOCGWINSZ)
in lib/sh/winsize.c:get_new_window_size()
.
move_to_high_fd()
wird im Allgemeinen mit allen temporären Dateideskriptoren verwendet, die von bash
(Skriptdateien, Pipes usw.) verwendet werden, daher die Verwirrung in den meisten Kommentaren, die bei Google-Suchanfragen häufig vorkommen.
Die intern von bash
einschließlich verwendeten Dateideskriptoren shell_tty
sind alle auf close-on-exec eingestellt, damit sie nicht an Befehle weitergegeben werden.