Wie kann man den richtigen Namen des steuernden Terminals (wenn es einen gibt, sonst einen Fehler) als Pfadnamen erhalten?
Mit "richtiger Name" meine ich nicht /dev/tty
, was nicht von anderen willkürlichen Prozessen verwendet werden kann, um auf dasselbe Terminal zu verweisen. Ich bevorzuge die Antwort wenn möglich als einfachen Shell-Code (wie im folgenden Beispiel), ansonsten als C-Funktion.
Beachten Sie, dass dies auch dann funktionieren muss, wenn die Standardeingabe umgeleitet wird, damit das tty
Dienstprogramm nicht verwendet werden kann: In einem not a tty
solchen Fall wird ein Fehler angezeigt, da tty
nur der Dateiname des mit der Standardeingabe verbundenen Terminals gedruckt wird.
Unter Linux kann man verwenden:
echo "/dev/`ps -p $$ -o tty | tail -n 1`"
Dies ist jedoch nicht portierbar, da laut POSIX das Format des Terminalnamens nicht angegeben ist .
Bei C-Funktionen wird ctermid (NULL)
zurückgegeben /dev/tty
, was hier unbrauchbar ist.
Hinweis: Laut zsh
Dokumentation sollte man dazu in der Lage sein
zsh -c 'echo $TTY'
Dies schlägt jedoch derzeit (Version 5.0.7) fehl, wenn sowohl die Standardeingabe als auch die Standardeingabe umgeleitet werden:
$ zsh -c 'echo $TTY > /dev/tty' < /dev/null
/dev/pts/9
$ zsh -c 'echo $TTY > /dev/tty' < /dev/null > /dev/null
/dev/tty
quelle
ps
Lösung die meisten Systeme abdeckt (undwho
nicht mehr hilft alsps
), möglicherweise mit etwas mehr Code, um den Bezeichner alleine zu behandeln (wie "04"). Ich habe mich gefragt, ob es eine noch tragbarere Lösung gibt.man xterm
:-Sccn
Diese Option ermöglichtxterm
die Verwendung als E / A-Kanal für ein vorhandenes Programm ... Der Optionswert besteht aus einigen Buchstaben des Namens einer Pty, die im Slave-Modus verwendet werden soll, sowie der geerbten FD-Nummer. Wenn die Option ein "/" -Zeichen enthält, wird der pty-Name vom fd abgegrenzt.ps
der Busybox (die von Android, BTW verwendet wird) funktioniert , auch nicht unter GNU / Linux. Was meinst du mit "xterm
kann damit umgehen04
"?busybox
ist nicht POSIX-konform.toybox
macht sich jedoch sehr gut.Antworten:
Das "steuernde Terminal" aka. ctty unterscheidet sich von " dem Terminal, mit dem ein Prozess interagiert".
Der Standardweg, um den Pfad von ctty zu erhalten, ist ctermid (3). Beim Aufrufen von In freebsd seit Release 10 wird ein tatsächlicher Pfad nachgeschlagen [1], während ältere freebsd und glibc-Implementierungen [2] bedingungslos "/ dev / tty"] zurückgeben.
ps (1) aus dem Linux procps 3.2.8-Paket, lesen Sie den numerischen Eintrag in / proc / * / stat [3] und ziehen Sie den Pfadnamen teilweise durch Raten ab [4, 5] aufgrund mangelnder [6]. .
Wenn wir jedoch nicht ausschließlich an der ctty interessiert sind, sondern an einem mit stdio verknüpften Terminal, gibt tty (1) den mit stdin verbundenen Terminalpfad aus, der mit identisch ist
ttyname(fileno(stdin))
c , und eine Alternative istreadlink /proc/self/fd/0
.Weniger wichtige Überlegungen zum bedingungslosen Verhalten von "/ dev / tty": Die Angaben besagen lediglich, dass die von ctermid zurückgegebene Zeichenfolge "bei Verwendung als Pfadname auf das aktuelle Steuerterminal verweisen" "anstelle eines einfachen" der Pfadname des aktuellen Steuerterminal ". Es könnte so interpretiert werden, dass "/ dev / tty" nicht das steuernde Terminal ist, sondern sich nur auf das steuernde Terminal bezieht, wenn derselbe Prozess es öffnet (3). Ein Verstoß gegen die Regel "Ein Terminal darf höchstens für eine Sitzung geeignet sein" [7].
Eine weitere Konsequenz ist, dass ctermid nicht ausfällt, wenn ich kein steuerndes Terminal habe - ein solches Versagen ist nach den Spezifikationen zulässig [8] -, sodass ich mich meiner Ungewissheit nur bewusst werden kann, bis ein nachfolgendes Öffnen fehlschlägt (3). Das ist in Ordnung, da die Spezifikationen auch besagen, dass ein Aufruf von open (3) nicht garantiert ist, um erfolgreich zu sein.
quelle
ps
Lösung, die ich in meiner Frage angegeben habe, da nicht alle Betriebssysteme über ein/proc
Dateisystem verfügen . Beachten Sie, dassps
selbst ein Readlink verwendet wird/proc/self/fd/2
(was auch dann funktioniert, wenn der Standardfehler umgeleitet wird).tty
.stderr
ist wahrscheinlich das beste, weil es spezifiziert offen r / w sein soll. Alsotty <&2
.ctermid()
Rückkehr nicht konform ist"/dev/tty"
. Dieser Name bezieht sich immer auf das steuernde Terminal des Prozesses, der darauf zugreift , was je nach Sitzung variiert. Das Terminal ist sitzungsspezifisch, der Name, auf den zugegriffen wird, muss jedoch nicht sein.Die POSIX-Spezifikation sichert ihre Wetten in Bezug auf das Controlling-Terminal wirklich ab und definiert sie folgendermaßen:
/dev/tty
ist ein Synonym für das steuernde Terminal, das einem Prozess zugeordnet ist.Das steht in der Definitionsliste - und das ist alles, was es gibt. In der allgemeinen Terminalschnittstelle wird jedoch noch mehr gesagt:
Ein Terminal kann als steuerndes Terminal zu einem Prozess gehören. Jeder Prozess einer Sitzung mit einem steuernden Terminal verfügt über dasselbe steuernde Terminal. Ein Terminal kann das steuernde Terminal für höchstens eine Sitzung sein. Das steuernde Terminal für eine Sitzung wird vom Sitzungsleiter auf implementierungsdefinierte Weise zugewiesen. Wenn ein Sitzungsleiter kein steuerndes Terminal hat und eine Terminalgerätedatei öffnet, die noch keiner Sitzung zugeordnet ist, ohne die Option O_NOCTTY zu verwenden (siehe open ()), wird durch die Implementierung definiert, ob das Terminal zum steuernden Terminal der Sitzung wird Führer.
Das steuernde Terminal wird während eines Funktionsaufrufs von fork () von einem untergeordneten Prozess geerbt. Ein Prozess gibt sein steuerndes Terminal auf, wenn er eine neue Sitzung mit dem erstellt
setsid()
Funktion; Andere Prozesse in der alten Sitzung, die dieses Terminal als steuerndes Terminal hatten, haben es weiterhin. Nach dem Schließen des letzten Dateideskriptors im System (unabhängig davon, ob er sich in der aktuellen Sitzung befindet oder nicht), der dem steuernden Terminal zugeordnet ist, wird nicht angegeben, ob alle Prozesse, die dieses Terminal als steuerndes Terminal hatten, kein steuerndes Terminal mehr haben. Ob und wie ein Sitzungsleiter ein steuerndes Terminal wieder erwerben kann, nachdem das steuernde Terminal auf diese Weise aufgegeben wurde, ist nicht spezifiziert. Ein Prozess gibt sein steuerndes Terminal nicht einfach auf, indem er alle dem steuernden Terminal zugeordneten Dateideskriptoren schließt, wenn andere Prozesse es weiterhin geöffnet haben.Es gibt eine Menge, die nicht spezifiziert ist - und ehrlich gesagt denke ich, dass es Sinn macht. Während das Terminal eine wichtige Benutzeroberfläche ist, gibt es in einigen Fällen auch alle möglichen anderen Dinge - wie die tatsächliche Hardware oder sogar eine Art Drucker -, aber in vielen Fällen ist es praktisch gar nichts - wie ein
xterm
ein Emulator, der nur ein Emulator ist . Es ist schwer, dort spezifisch zu werden - und ich denke, es wäre sowieso nicht viel im Interesse von Unix, da Terminals viel mehr als Unix leisten.Wie auch immer, POSIX ist auch ziemlich zweifelhaft, wie
ps
sich verhalten soll, wenn es um die Ctty geht.Da ist der
-a
Schalter:Groß. Sitzungsleiter können weggelassen werden. Das ist nicht sehr hilfreich.
Und
-t
:<blank>
oder durch Kommas getrennten Liste ist. Terminal-IDs müssen in einem implementierungsdefinierten Format angegeben werden.... was eine weitere Enttäuschung ist. Über XSI-Systeme heißt es jedoch weiter:
tty04
) oder, wenn der Dateiname des Geräts mit beginnttty
, nur der nach den Zeichen folgenden Kennungtty
(z. B.04
) .Das ist ein bisschen besser, aber kein Weg. Auch auf XSI-Systemen gibt es den
-d
Schalter:... was zumindest klar ist. Sie können den
-o
utput-Schalter auch mit der Formatzeichenfolge angebentty
, aber wie Sie bereits bemerkt haben, ist das Ausgabeformat implementierungsdefiniert. Trotzdem denke ich, dass es so gut ist, wie es nur geht. Ich denke, dass - mit viel Arbeit - die oben genannten Schalter in Kombination mit einigen anderen Dienstprogrammen Ihnen einen ziemlich guten Ballpark bringen können. Um ganz ehrlich zu sein, ich weiß nicht, wann / wie es für Sie kaputt geht - und ich konnte mir keine Situation vorstellen, in der es passieren würde. Aber ich denke wahrscheinlich, wenn wir hinzufügenfuser
undfind
den Pfad überprüfen können.Das
/dev/null
Zeug sollte nur zeigen, dass es funktionieren kann, wenn keine der suchenden Subshells 0,1,2 mit der CTTY verbunden hat. Wie auch immer, das druckt:Jetzt erhält das oben Genannte den vollständigen Pfad auf meiner Maschine, und ich kann mir vorstellen, dass dies in den meisten Fällen für die meisten Menschen der Fall ist. Ich kann mir auch vorstellen, dass es scheitern könnte. Es sind nur grobe Heuristiken.
Dies könnte wahrscheinlich aus vielen anderen Gründen fehlschlagen, aber wenn Sie sich auf einem System befinden, das es dem Sitzungsleiter ermöglicht, alle Deskriptoren an die ctty abzugeben und dennoch die Seite zu bleiben, wie es die Spezifikation zulässt, wird dies definitiv nicht helfen. Trotzdem denke ich, dass dies in den meisten Fällen eine ziemlich gute Schätzung erhalten kann.
Natürlich ist die einfachste zu tun , was , wenn Sie keine Deskriptoren zu Ihrem CTTY verbunden ist nur ...
...o.ä.
quelle