¿Cómo identificar el terminal desde un script?

8

Y no digas " $TERM", siempre es así xterm.

¿Cómo puede un bashscript decir en qué terminal se está ejecutando, específicamente si es iTerm, Terminal.app o realmente un xterm?

Pregunto porque resetno funciona¹ fuera de la caja en Terminal.app e iTerm2. iTerm2, sin embargo, reconoce una secuencia de escape para hacer un reinicio de terminal ( \x1b]50;ClearScrollback\x07), y si pudiera detectarlo, podría anularlo resetcon un alias que haga lo correcto. AFAICT, Terminal.app carece de una secuencia de reinicio, y las personas recurren a la ridícula piratería informática para hackear eso .

Mi objetivo final aquí es tener resetel mismo trabajo si estoy trabajando en OS X o Linux, trabajando local o remotamente a través de SSH. (No quiero tener que intentar recordar cuál, y es útil hacer reset && command-that-outputs-a-bunchy tener trabajo de entrada). Terminal.app e iTerm están tirando una llave en este plan al no implementarse resetcorrectamente.

Esto significa que simplemente anular resetno lo es todo: si estoy en una máquina Linux, necesita saber si estoy usando gnome-terminalo iTerm para enviar la secuencia de escape correcta.

¿Hay alguna manera (incluso si necesito un ioctl) de preguntarle al terminal qué es realmente ?

¹ Para los fines de esta pregunta, el reinicio debe borrar la pantalla, reiniciar el cursor y borrar el búfer de desplazamiento.

Thanatos
fuente
Bueno, esta es una característica, no un error, o eso dicen. ¿Qué sucede si abre Terminal.appla configuración, la pestaña del terminal y establece las líneas de desplazamiento en 0? ¿Deshabilita todo el texto sobre la línea actual, o simplemente cualquier cosa sobre la parte superior de la pantalla? Lo sé, no es exactamente lo que pediste, vale la pena intentarlo.
nitro2k01
@ nitro2k01: ¿No estoy seguro de lo que eso lograría? Yo quiero desplazamiento hacia atrás. Solo quiero poder borrarlo de vez en cuando, preferiblemente con reset, ya que eso es lo que mis dedos saben.
Thanatos
En cuanto a su problema de "reinicio": para aclarar, está esperando que el resetcomando borre el contenido de desplazamiento hacia atrás del emulador de terminal, pero no se garantiza que lo haga, porque el desplazamiento hacia atrás es una característica específica del emulador de terminal, no realmente un parte de una terminal. Sin embargo, Terminal admite una extensión de la secuencia de escape ED (Erase in Display) para borrar el desplazamiento hacia atrás ESC [ 3 J. Puede borrar la pantalla y luego usar eso, por ejemploreset && printf '\e[3J’
Chris Page
Vea mi respuesta aquí apple.stackexchange.com/a/113168/6883 para obtener más detalles sobre la extensión Borrar en pantalla.
Chris Page
@ChrisPage: me doy cuenta de que los terminales son cosas extravagantes, pero si declaras que eres un xterm(a través de TERM=xterm) espero que emules un superconjunto del XTerm, que borra su retroceso al reiniciar. (Al igual que si enviaras la secuencia de escape para "azul", esperarías azul). Por supuesto, mi xterm me dice eso Erase is backspace., y estoy agradecido de que nada más lo haga; Eso es molesto.
Thanatos

Respuestas:

10

Uso $TERM_PROGRAM.

iTerm lo establece en iTerm.app, y Terminal.app en Apple_Terminal.

Daniel Beck
fuente
Je, vale, esto es claramente mejor que mi truco, +1 :). Sin embargo, el truco debería funcionar para cualquier emulador de terminal, no solo para esos dos.
terdon
No hay una sola forma de detectar cada emulador de terminal. Para xterm, puede verificar la variable $ XTERM_VERSION, por ejemplo. Eso se encargará de lo que probablemente sean los tres emuladores más populares en OS X.
Chris Page
Aceptar esto, ya que es un buen comienzo. Desafortunadamente, no es tan fácil, ya que esta variable no está disponible dentro de una sesión SSH. Sospecho que hay configuraciones que puedo editar para reenviarlo.
Thanatos
1
@Thanatos sshd_configque está AcceptEnvprobablemente. Como esto (su shell se ejecuta en un host diferente al que ejecuta su Terminal) es información muy importante, realmente debería ser parte de la pregunta.
Daniel Beck
@DanielBeck: No es estrictamente el caso; Me gustaría hacer lo mismo local y remotamente. Lo que quiero decir es que escribir "reset" en un terminal provoca un reinicio del terminal, sin importar si estoy en OS X o Linux, trabajando localmente o de forma remota. He editado esto en la pregunta.
Thanatos
1

$TERMno tiene nada que ver con el emulador de terminal que se está ejecutando actualmente, es solo su terminal predeterminado y se puede configurar para cualquier cosa. Para obtener el nombre del emulador de terminal que está ejecutando, puede usar pspara obtener el PID del proceso principal de su shell actual.

NOTA: Lo siguiente fallará en OSX pero debería funcionar bien en Linux

El PID de su proceso actual de shell es $$. A partir de ahí, puede usar pspara mostrar un árbol de procesos e imprimir el PID del padre de su sesión de shell actual:

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

Luego puede pasar ese PID psy decirle que imprima el nombre del comando:

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

Eso truncará el nombre, debería ser suficiente para que lo descubras, pero podría no ser bueno para las secuencias de comandos. Para obtener el nombre completo, puedes intentar

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

Esto es lo que obtengo en mi sistema usando algunas terminales diferentes:

  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
fuente
No funciona en OS X:ps: illegal option -- f
Daniel Beck
@DanielBeck maldito estilo BSD, gracias. ¿Podría intentarlo nuevamente con la versión actualizada? Agregar un -antes de las opciones debería funcionar de acuerdo con OSX man ps.
terdon
Mejor, pero aún no funciona. El formato de salida es diferente (PID es $2, PPID es $3), y el proceso padre del shell puede ser login(según la configuración del Terminal), con diferentes parámetros. Sin embargo, su proceso padre es Terminal. --no-headersno existe, necesitarías algo así tail -n1. Y dado que todos los procesos con UI tienen un argumento-psn_0_... , awk '{print $NF}'tampoco funciona.
Daniel Beck
@DanielBeck bien, entonces. OK, gracias, dejaré en claro que esto falla en OSX.
terdon
Tenga en cuenta que esto solo funciona localmente. No puede utilizar este enfoque para averiguar qué emulador de terminal se está utilizando en un cliente remoto. La mejor respuesta es buscar variables como $ TERM_PROGRAM (como se menciona en la respuesta de @ DanielBeck) y $ XTERM_VERSION para deducir la aplicación del emulador.
Chris Page
0

Aquí hay una forma portátil de obtener el nombre o la ruta del proceso principal:

iTerm 2:

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

gnome-terminal en Ubuntu:

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

Terminal.app:

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

Tenga en cuenta que si Terminal.app está configurado para abrir nuevos shells con el shell de inicio de sesión predeterminado, el proceso principal del shell es loginy no el terminal.

La commcolumna es la ruta completa del comando en OS X y el nombre del comando truncado a 15 caracteres en la implementación de procps en Linux.

Lri
fuente
Intenté iTerm y obtuve login: ¿Personalicé mi perfil hace algún tiempo para ejecutar el comando login -fp danielbeck?
Daniel Beck