Comment identifier le terminal à partir d'un script?

8

Et ne dites pas " $TERM" - c'est toujours xterm.

Comment un bashscript peut-il dire dans quel terminal il s'exécute, en particulier s'il s'agit d'iTerm, Terminal.app ou en fait d'un xterm?

Je demande parce resetque ne fonctionne pas¹ sur la base de Terminal.app et iTerm2. iTerm2, cependant, reconnaît une séquence d'échappement pour effectuer une réinitialisation du terminal ( \x1b]50;ClearScrollback\x07), et si je pouvais la détecter, je pourrais remplacer resetavec un alias qui fait la bonne chose. AFAICT, Terminal.app n'a pas de séquence de réinitialisation, et les gens ont recours à un piratage ridicule pour pirater cela .

Mon objectif final ici est d'avoir resetle même travail que je travaille sur OS X ou Linux, en travaillant localement ou à distance via SSH. (Je ne veux pas avoir à essayer de me rappeler lequel, et il est utile de le faire reset && command-that-outputs-a-bunchet d'avoir un travail de mise à jour.) Terminal.app et iTerm jettent une clé dans ce plan en ne l'implémentant pas resetcorrectement.

Cela signifie que simplement remplacer resetn'est pas tout à fait ça: si je suis sur une machine Linux, il doit savoir si j'utilise gnome-terminalou iTerm afin d'envoyer la bonne séquence d'échappement.

Existe-t-il un moyen (même si j'en ai besoin ioctl) de demander au terminal ce que c'est vraiment ?

¹Pour les besoins de cette question, la réinitialisation doit effacer l'écran, réinitialiser le curseur et effacer le tampon de défilement.

Thanatos
la source
Eh bien, c'est une fonctionnalité, pas un bug, du moins disent-ils. Que se passe-t-il si vous ouvrez Terminal.apples paramètres, l'onglet du terminal et définissez les lignes de défilement sur 0? Est-ce que cela désactive tout ou partie du texte au-dessus de la ligne actuelle, ou tout simplement au-dessus du haut de l'écran? Je sais, ce n'est pas exactement ce que tu as demandé, ça vaut le coup.
nitro2k01
@ nitro2k01: Je ne sais pas ce que cela accomplirait? Je veux revenir en arrière. Je veux juste pouvoir l'effacer de temps en temps, de préférence avec reset, car c'est ce que mes doigts savent.
Thanatos
En ce qui concerne votre problème de «réinitialisation»: pour clarifier, vous vous attendez à ce que la resetcommande efface le contenu de défilement arrière de l'émulateur de terminal, mais ce n'est pas garanti, car le défilement arrière est une fonctionnalité spécifique à l'émulateur de terminal, pas vraiment une partie d'un terminal. Cependant, Terminal prend en charge une extension de la séquence d'échappement ED (Erase in Display) pour effacer le défilement arrière ESC [ 3 J. Vous pouvez effacer l'écran, puis l'utiliser, par exemple,reset && printf '\e[3J’
Chris Page
Voir ma réponse ici apple.stackexchange.com/a/113168/6883 pour plus de détails sur l'extension Erase in Display.
Chris Page
@ChrisPage: Je me rends compte que les terminaux sont des choses excentriques, mais si vous vous déclarez un xterm(à travers TERM=xterm), je m'attends à ce que vous émuliez un surensemble de l'XTerm, qui efface son défilement lors de la réinitialisation. (Tout comme si vous aviez envoyé la séquence d'échappement pour "bleu", vous vous attendriez à bleu.) Certes, mon xterm me le dit Erase is backspace., ce que je ne suis reconnaissant de rien d'autre; c'est juste ennuyeux.
Thanatos

Réponses:

10

Utilisez $TERM_PROGRAM.

iTerm le définit sur iTerm.app, et Terminal.app sur Apple_Terminal.

Daniel Beck
la source
Hé, OK, c'est clairement mieux que mon hack, +1 :). Le hack devrait cependant fonctionner pour n'importe quel émulateur de terminal, pas seulement pour ces deux-là.
terdon
Il n'y a pas de moyen unique de détecter chaque émulateur de terminal. Pour xterm, vous pouvez vérifier la variable $ XTERM_VERSION, par exemple. Cela prendra en charge ce qui est probablement les trois émulateurs les plus populaires sur OS X.
Chris Page
Accepter cela, car c'est un bon début. Malheureusement, ce n'est pas aussi simple, car cette variable n'est pas disponible dans une session SSH. Je soupçonne qu'il existe des configurations que je peux modifier pour les transmettre.
Thanatos
1
@Thanatos sshd_configest AcceptEnvprobablement. Comme cela (votre shell fonctionne sur un hôte différent de celui sur lequel votre terminal fonctionne) est une information très importante, cela devrait vraiment faire partie de la question.
Daniel Beck
@DanielBeck: Ce n'est pas strictement le cas; Je voudrais faire la même chose localement et à distance. Ce que je veux dire, c'est que taper "reset" dans un terminal provoque une réinitialisation du terminal, que je sois sous OS X ou Linux, travaillant localement ou à distance. J'ai édité cela dans la question.
Thanatos
1

$TERMn'a rien à voir avec l'émulateur de terminal en cours d'exécution, c'est juste votre terminal par défaut et peut être réglé sur n'importe quoi. Pour obtenir le nom de l'émulateur de terminal que vous exécutez, vous pouvez utiliser pspour obtenir le PID du processus parent de votre shell actuel.

REMARQUE: ce qui suit échouera sous OSX mais devrait fonctionner correctement sous Linux

Le PID de votre processus shell actuel est $$. À partir de là, vous pouvez utiliser pspour afficher un arbre de processus et imprimer le PID du parent de votre session shell actuelle:

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

Vous pouvez ensuite transmettre ce PID à pset lui dire d'imprimer le nom de la commande:

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

Cela tronquera le nom, il devrait vous suffire de le comprendre, mais pourrait ne pas être bon pour les scripts. Pour obtenir le nom complet, vous pouvez essayer

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

Voici ce que j'obtiens sur mon système en utilisant plusieurs terminaux différents:

  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
la source
Ne fonctionne pas sur OS X:ps: illegal option -- f
Daniel Beck
@DanielBeck darn style BSD, merci. Pourriez-vous réessayer avec la version mise à jour? L'ajout d'un -avant les options devrait fonctionner selon OSX man ps.
terdon
Mieux, mais ne fonctionne toujours pas. Le format de sortie est différent (PID est $2, PPID est $3), et le processus parent du shell peut être login(selon la configuration du terminal), avec différents paramètres. Cependant, son processus parent l'est Terminal. --no-headersn'existe pas, vous auriez besoin de quelque chose comme tail -n1. Et puisque tous les processus avec UI ont un argument-psn_0_... , awk '{print $NF}'cela ne fonctionne pas non plus.
Daniel Beck
@DanielBeck se dérobe bien alors. OK, merci, je vais préciser que cela échoue sur OSX.
terdon
Notez que cela ne fonctionne que localement. Vous ne pouvez pas utiliser cette approche pour déterminer quel émulateur de terminal est utilisé sur un client distant. La meilleure réponse consiste à rechercher des variables comme $ TERM_PROGRAM (comme mentionné dans la réponse de @ DanielBeck) et $ XTERM_VERSION pour déduire l'application d'émulation.
Chris Page
0

Voici un moyen portable d'obtenir le nom ou le chemin du processus parent:

iTerm 2:

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

gnome-terminal dans Ubuntu:

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

Terminal.app:

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

Notez que si Terminal.app est défini pour ouvrir de nouveaux shells avec le shell de connexion par défaut, le processus parent du shell est loginet non le terminal.

La commcolonne est le chemin complet de la commande sous OS X et le nom de la commande tronqué à 15 caractères dans l'implémentation procps sous Linux.

Lri
la source
J'ai essayé dans iTerm et j'ai obtenu login- Ai-je personnalisé mon profil quelque temps en arrière pour exécuter la commande login -fp danielbeck?
Daniel Beck