Wie identifiziere ich das Terminal anhand eines Skripts?

8

Und sag nicht " $TERM" - es ist immer xterm.

Wie kann ein bashSkript feststellen, in welchem ​​Terminal es ausgeführt wird, insbesondere ob es sich um iTerm, Terminal.app oder tatsächlich um ein xterm handelt?

Ich frage, weil resetes auf Terminal.app und iTerm2 nicht sofort funktioniert¹. iTerm2 erkennt jedoch eine Escape-Sequenz für einen Terminal-Reset ( \x1b]50;ClearScrollback\x07), und wenn ich sie erkennen könnte, könnte ich sie resetmit einem Alias überschreiben , der das Richtige tut. AFAICT, Terminal.app fehlt eine Reset-Sequenz, und die Leute greifen auf lächerliche Tom-Hackery zurück, um das zu umgehen .

Mein Endziel hier ist es, dass resetich genauso arbeite, egal ob ich unter OS X oder Linux arbeite, lokal oder remote über SSH. (Ich möchte nicht versuchen müssen, mich an welche zu erinnern, und es ist nützlich, reset && command-that-outputs-a-bunchUp-Enter-Arbeiten auszuführen.) Terminal.app und iTerm werfen einen Schraubenschlüssel in diesen Plan, indem sie nicht resetkorrekt implementiert werden.

Das bedeutet, dass das einfache Überschreiben resetnicht ganz gnome-terminaldas Richtige ist: Wenn ich auf einem Linux-Computer bin, muss es wissen, ob ich oder iTerm verwende, um die richtige Escape-Sequenz zu senden.

Gibt es eine Möglichkeit (auch wenn ich eine brauche ioctl), das Terminal zu fragen, was es wirklich ist?

¹Für die Zwecke dieser Frage sollte durch Zurücksetzen der Bildschirm gelöscht, der Cursor zurückgesetzt und der Bildlaufpuffer gelöscht werden.

Thanatos
quelle
Nun, das ist eine Funktion, kein Fehler, oder so sagen sie. Was passiert, wenn Sie Terminal.appdie Einstellungen und die Registerkarte "Terminal" öffnen und die Bildlaufzeilen auf 0 setzen? Deaktiviert das jeglichen Text über der aktuellen Zeile oder nur irgendetwas über dem oberen Bildschirmrand? Ich weiß, es ist nicht genau das, wonach Sie gefragt haben, einen Versuch wert.
nitro2k01
@ nitro2k01: Ich bin nicht sicher, was das bewirken würde? Ich möchte einen Scrollback. Ich möchte es nur ab und zu löschen können, vorzugsweise mit reset, da meine Finger das wissen.
Thanatos
Was Ihr Problem beim Zurücksetzen betrifft: Zur Verdeutlichung erwarten Sie, dass der resetBefehl den Scrollback-Inhalt des Terminalemulators löscht. Dies ist jedoch nicht garantiert, da das Scrollback eine Terminalemulator-spezifische Funktion ist, nicht wirklich eine Teil eines Terminals. Terminal unterstützt jedoch eine Erweiterung der ED-Escape-Sequenz (Erase in Display), um das Zurückblättern zu löschen ESC [ 3 J. Sie können den Bildschirm löschen und dann verwenden, z. B.reset && printf '\e[3J’
Chris Page
Weitere Informationen zur Erweiterung "In Anzeige löschen" finden Sie in meiner Antwort hier apple.stackexchange.com/a/113168/6883 .
Chris Seite
@ChrisPage: Mir ist klar, dass Terminals eigenartige Dinge sind, aber wenn Sie sich als xterm(durch TERM=xterm) deklarieren, würde ich erwarten, dass Sie eine Obermenge des XTerm emulieren, die beim Zurücksetzen den Scrollback löscht. (Als ob Sie die Escape-Sequenz für "blau" gesendet hätten, würden Sie blau erwarten.) Zugegeben, mein xterm sagt mir das Erase is backspace., was ich dankbar bin, dass nichts anderes tut; das ist nur nervig
Thanatos

Antworten:

10

Verwenden Sie $TERM_PROGRAM.

iTerm setzt es auf iTerm.appund Terminal.app auf Apple_Terminal.

Daniel Beck
quelle
Heh, OK, das ist eindeutig besser als mein Hack, +1 :). Der Hack sollte jedoch für jeden Terminalemulator funktionieren, nicht nur für diese beiden.
Terdon
Es gibt keine einzige Möglichkeit, jeden Terminalemulator zu erkennen. Für xterm können Sie beispielsweise nach der Variablen $ XTERM_VERSION suchen. Das wird sich um die wahrscheinlich drei beliebtesten Emulatoren unter OS X kümmern.
Chris Seite
Akzeptiere dies, da es ein guter Anfang ist. Leider ist es nicht ganz so einfach, da diese Variable in einer SSH-Sitzung nicht verfügbar ist. Ich vermute, dass es Konfigurationen gibt, die ich bearbeiten kann, um sie weiterzuleiten.
Thanatos
1
@Thanatos sshd_config‚s AcceptEnvwahrscheinlich. Da dies (Ihre Shell läuft auf einem anderen Host als dem, auf dem Ihr Terminal ausgeführt wird) sehr wichtige Informationen sind, sollte es wirklich Teil der Frage sein.
Daniel Beck
@ DanielBeck: Das ist nicht unbedingt der Fall; Ich möchte dasselbe lokal und remote tun. Was ich anstrebe, ist, dass das Eingeben von "Zurücksetzen" in ein Terminal ein Zurücksetzen des Terminals bewirkt, unabhängig davon, ob ich unter OS X oder Linux arbeite oder lokal oder remote arbeite. Ich habe dies in die Frage bearbeitet.
Thanatos
1

$TERMhat überhaupt nichts mit dem aktuell laufenden Terminalemulator zu tun, es ist nur Ihr Standardterminal und kann auf alles eingestellt werden. Um den Namen des Terminalemulators abzurufen, den Sie ausführen, können Sie psdie PID des übergeordneten Prozesses Ihrer aktuellen Shell abrufen.

HINWEIS: Folgendes schlägt unter OSX fehl, sollte jedoch unter Linux einwandfrei funktionieren

Die PID Ihres aktuellen Shell-Prozesses ist $$. Von dort aus können Sie pseinen Prozessbaum anzeigen und die PID des übergeordneten Elements Ihrer aktuellen Shell-Sitzung drucken:

ps -axjf | awk -v pid=$$ '($2==pid){print $1}'

Sie können diese PID dann an übergeben psund anweisen, den Befehlsnamen auszudrucken:

ps -o comm=  $(ps -axjf | awk -v pid=$$ '($2==pid){print $1}')

Dadurch wird der Name abgeschnitten. Es sollte ausreichen, um ihn herauszufinden, ist jedoch möglicherweise nicht für die Skripterstellung geeignet. Um den vollständigen Namen zu erhalten, können Sie versuchen

ps --no-headers $(ps -axjf | awk -v pid=$$ '($2==pid){print $1}') | awk '{print $NF}'

Dies ist, was ich auf meinem System mit ein paar verschiedenen Terminals bekomme:

  1. terminator

    $ ps --no-headers $(ps -axjf | awk -v pid=$$ '($2==pid){print $1}') | 
       awk '{print $NF}'
    /usr/bin/x-terminal-emulator
    
  2. gnome-terminal

    $ ps --no-headers $(ps -axjf | awk -v pid=$$ '($2==pid){print $1}') | 
       awk '{print $NF}'
    /usr/lib/gnome-terminal/gnome-terminal-server
    
  3. xterm

    $ ps --no-headers $(ps axjf | awk -v pid=$$ '($2==pid){print $1}') | 
       awk '{print $NF}'
    xterm
    
Terdon
quelle
Funktioniert nicht unter OS X:ps: illegal option -- f
Daniel Beck
@ DanielBeck verdammter BSD-Stil, danke. Könnten Sie es mit der aktualisierten Version erneut versuchen? Das Hinzufügen von a -vor den Optionen sollte gemäß OSX funktionieren man ps.
Terdon
Besser, aber immer noch nicht funktionierend. Das Ausgabeformat ist unterschiedlich (PID ist $2, PPID ist $3) und der übergeordnete Prozess der Shell kann login(abhängig von der Terminalkonfiguration) mit unterschiedlichen Parametern sein. Doch sein ist geordneten Prozess Terminal. --no-headersexistiert nicht, du brauchst so etwas tail -n1. Und da alle Prozesse mit UI ein Argument haben-psn_0_... , awk '{print $NF}'funktioniert es auch nicht.
Daniel Beck
@ DanielBeck gut shucks dann. OK, danke, ich werde klarstellen, dass dies unter OSX fehlschlägt.
Terdon
Beachten Sie, dass dies nur lokal funktioniert. Mit diesem Ansatz können Sie nicht herausfinden, welcher Terminalemulator auf einem Remoteclient verwendet wird. Die beste Antwort ist, nach Variablen wie $ TERM_PROGRAM (wie in der Antwort von @ DanielBeck erwähnt) und $ XTERM_VERSION zu suchen, um die Emulatoranwendung abzuleiten.
Chris Seite
0

Hier ist eine tragbare Methode, um den Namen oder Pfad des übergeordneten Prozesses abzurufen:

iTerm 2:

$ ps -p $(ps -p $$ -o ppid=) -o comm=
/Applications/iTerm.app/Contents/MacOS/iTerm

Gnom-Terminal in Ubuntu:

$ ps -p $(ps -p $$ -o ppid=) -o comm=
gnome-terminal

Terminal.app:

$ ps -p $(ps -p $$ -o ppid=) -o comm=
login

Beachten Sie, dass, wenn Terminal.app so eingestellt ist, dass neue Shells mit der Standard-Login-Shell geöffnet werden, der übergeordnete Prozess der Shell loginund nicht das Terminal ist.

Die commSpalte ist der vollständige Pfad des Befehls in OS X und der Befehlsname, der in der procps-Implementierung unter Linux auf 15 Zeichen gekürzt wurde.

Lri
quelle
Versucht in iTerm und bekam login- Habe ich mein Profil vor einiger Zeit angepasst, um den Befehl auszuführen login -fp danielbeck?
Daniel Beck