Come identificare il terminale da uno script?


8

E non dire " $TERM" - è sempre xterm.

Come può uno bashscript dire in quale terminale è in esecuzione, in particolare se è iTerm, Terminal.app o effettivamente un xterm?

Chiedo perché resetnon funziona¹ out of the box su Terminal.app e iTerm2. iTerm2, tuttavia, riconosce una sequenza di escape per eseguire un reset del terminale ( \x1b]50;ClearScrollback\x07), e se potessi rilevarlo, potrei scavalcare resetcon un alias che fa la cosa giusta. AFAICT, Terminal.app non ha una sequenza di reset, e la gente ricorre a un ridicolo hacker tom per aggirarlo .

Il mio obiettivo finale qui è di avere resetlo stesso lavoro se sto lavorando su OS X o Linux, lavorando localmente o da remoto tramite SSH. (Non voglio provare a ricordare quale, ed è utile fare reset && command-that-outputs-a-bunche avere il lavoro di inserimento). Terminal.app e iTerm stanno lanciando una chiave in questo piano non implementando resetcorrettamente.

Questo significa che semplicemente ignorare resetnon è proprio così: se sono su una macchina Linux, deve sapere se sto usando gnome-terminalo iTerm per inviare la giusta sequenza di escape.

Esiste un modo (anche se ne ho bisogno ioctl) di chiedere al terminale che cos'è veramente ?

¹ Ai fini di questa domanda, il ripristino dovrebbe cancellare lo schermo, ripristinare il cursore e cancellare il buffer di scorrimento.


Bene, questa è una funzionalità, non un bug, o almeno così dicono. Cosa succede se si aprono Terminal.apple impostazioni, la scheda Terminale e si impostano le linee di scorrimento su 0? Ciò disabilita tutto il testo sopra la riga corrente o semplicemente qualcosa sopra la parte superiore dello schermo? Lo so, non è esattamente quello che hai chiesto, vale la pena provare.
nitro2k01

@ nitro2k01: non sono sicuro di cosa realizzerebbe? Io voglio scrollback. Voglio solo essere in grado di cancellarlo di tanto in tanto, preferibilmente con reset, poiché questo è ciò che le mie dita sanno.
Thanatos,

Per quanto riguarda il problema di "ripristino": per chiarire, ti aspetti che il resetcomando cancelli il contenuto di scorrimento dell'emulatore di terminale, ma non è garantito farlo, perché scroll-back è una funzione specifica dell'emulatore di terminale, non proprio un parte di un terminale. Tuttavia, Terminal supporta un'estensione della sequenza di escape ED (Erase in Display) per cancellare lo scroll-back ESC [ 3 J. È possibile cancellare lo schermo, quindi utilizzare, ad esempio, reset && printf '\e[3J’
Chris

Vedi la mia risposta qui apple.stackexchange.com/a/113168/6883 per maggiori dettagli sull'estensione Cancella nel display.
Chris Page

@ChrisPage: mi rendo conto che i terminali sono cose bizzarre, ma se ti dichiari un xterm(attraverso TERM=xterm) mi aspetto che tu emuli un superset di XTerm, che cancella il suo scrollback al reset. (Proprio come se avessi inviato la sequenza di escape per "blu", ti aspetteresti il ​​blu.) Concesso, il mio xterm mi dice che Erase is backspace., di cui sono grato, nient'altro; è solo fastidioso.
Thanatos

Risposte:


10

Usa $TERM_PROGRAM.

iTerm lo imposta su iTerm.appe Terminal.app su Apple_Terminal.


Heh, OK, questo è chiaramente meglio del mio hack, +1 :). L'hacking dovrebbe funzionare per qualsiasi emulatore di terminale, non solo per quei due.
Terdon,

Non esiste un solo modo per rilevare ogni emulatore di terminale. Per xterm, è possibile verificare la variabile $ XTERM_VERSION, ad esempio. Questo si occuperà di quelli che sono probabilmente i tre emulatori più popolari su OS X.
Chris Pagina

Accettarlo, dato che è un buon inizio. Sfortunatamente, non è così facile, poiché questa variabile non è disponibile all'interno di una sessione SSH. Sospetto che ci siano configurazioni che posso modificare per inoltrarlo.
Thanatos,

1
@Thanatos sshd_config's AcceptEnvprobabilmente. Poiché questa (la tua shell funziona su un host diverso da quello su cui è in esecuzione il tuo Terminale) è un'informazione molto importante, dovrebbe davvero far parte della domanda.
Daniel Beck

@DanielBeck: non è strettamente il caso; Mi piacerebbe fare lo stesso a livello locale e remoto. Quello che sto cercando è che digitare "reset" in un terminale provoca un reset del terminale, indipendentemente dal fatto che io sia su OS X o Linux, che lavori localmente o in remoto. L'ho modificato nella domanda.
Thanatos

1

$TERMnon ha nulla a che fare con l'emulatore di terminale attualmente in esecuzione, è solo il terminale predefinito e può essere impostato su qualsiasi cosa. Per ottenere il nome dell'emulatore di terminale in esecuzione, è possibile utilizzare psper ottenere il PID del processo padre della shell corrente.

NOTA: Quanto segue non funzionerà su OSX ma dovrebbe funzionare correttamente su Linux

Il PID del tuo attuale processo di shell è $$. Da lì, è possibile utilizzare psper mostrare un albero dei processi e stampare il PID del genitore della sessione di shell corrente:

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

È quindi possibile passare quel PID a pse dirgli di stampare il nome del comando:

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

Questo troncerà il nome, dovrebbe essere sufficiente per capirlo, ma potrebbe non essere buono per lo scripting. Per ottenere il nome completo, puoi provare

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

Questo è ciò che ottengo sul mio sistema utilizzando alcuni terminali diversi:

  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
    

Non funziona su OS X:ps: illegal option -- f
Daniel Beck

@DanielBeck darn stile BSD, grazie. Potresti riprovare con la versione aggiornata? L'aggiunta di una -prima delle opzioni dovrebbe funzionare secondo OSX man ps.
Terdon,

Meglio, ma ancora non funziona. Il formato di output è diverso (PID è $2, PPID è $3) e il processo padre della shell potrebbe essere login(a seconda della configurazione del Terminale), con parametri diversi. Tuttavia, il suo processo genitore è Terminal. --no-headersnon esiste, avresti bisogno di qualcosa del genere tail -n1. E poiché tutti i processi con l'interfaccia utente hanno un argomento-psn_0_... , awk '{print $NF}'non funziona neanche.
Daniel Beck

@DanielBeck fa schifo allora. OK, grazie chiarirò che questo non funziona su OSX.
Terdon,

Si noti che questo funziona solo localmente. Non è possibile utilizzare questo approccio per capire quale emulatore di terminale viene utilizzato su un client remoto. La risposta migliore è cercare variabili come $ TERM_PROGRAM (come menzionato nella risposta di @ DanielBeck) e $ XTERM_VERSION per dedurre l'applicazione dell'emulatore.
Chris Page

0

Ecco un modo portatile per ottenere il nome o il percorso del processo genitore:

iTerm 2:

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

gnome-terminal in Ubuntu:

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

Terminal.app:

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

Si noti che se Terminal.app è impostato per aprire nuove shell con la shell di accesso predefinita, il processo padre della shell è logine non il terminale.

La commcolonna è il percorso completo del comando in OS X e il nome del comando troncato a 15 caratteri nell'implementazione procps in Linux.


Ho provato a iTerm e ho ottenuto login- Ho personalizzato il mio profilo qualche tempo fa per eseguire il comando login -fp danielbeck?
Daniel Beck
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.