Como identificar o terminal de um script?

8

E não diga " $TERM" - é sempre xterm.

Como um bashscript pode dizer em qual terminal está sendo executado, especificamente se é iTerm, Terminal.app ou, na verdade, um xterm?

Eu pergunto porque resetnão funciona fora da caixa no Terminal.app e iTerm2. O iTerm2, no entanto, reconhece uma sequência de escape para fazer um reset de terminal ( \x1b]50;ClearScrollback\x07), e se eu pudesse detectá-lo, eu poderia substituir resetpor um alias que fizesse a coisa certa. AFAICT, Terminal.app não possui uma sequência de reinicialização, e as pessoas recorrem à ridícula tom-hacker para descobrir isso .

Meu objetivo final aqui é ter reseto mesmo trabalho, seja trabalhando no OS X ou Linux, trabalhando local ou remotamente através do SSH. (Eu não quero ter que tentar lembrar qual, e é útil fazer reset && command-that-outputs-a-bunche ter up-enter funcionar.) Terminal.app e iTerm estão jogando uma chave neste plano, não implementando resetcorretamente.

Isso significa que simplesmente resetnão há nada: se estou em uma máquina Linux, ele precisa saber se estou usando o gnome-terminaliTerm para enviar a sequência de escape correta.

Existe alguma maneira (mesmo se eu precisar de um ioctl) para perguntar ao terminal o que realmente é?

ThePara os fins desta questão, a reinicialização deve limpar a tela, redefinir o cursor e limpar o buffer de rolagem.

Thanatos
fonte
Bem, isso é uma característica, não um bug, ou assim eles dizem. O que acontece se você abrir Terminal.appas configurações, a guia do terminal e definir as linhas de rolagem para 0? Isso desativa todo e qualquer texto acima da linha atual, ou qualquer coisa acima da parte superior da tela? Eu sei, não é exatamente o que você pediu, vale um tiro.
nitro2k01
@ nitro2k01: Não tenho certeza o que isso iria conseguir? Eu quero rolar de volta. Eu só quero ser capaz de limpá-lo de vez em quando, de preferência com reset, já que é o que meus dedos sabem.
Thanatos
Quanto ao seu problema de "reset": para esclarecer, você está esperando o resetcomando para limpar o conteúdo de rolagem traseira do emulador de terminal, mas isso não é garantido para fazer isso, porque scroll-back é um recurso específico do emulador de terminal, não realmente um parte de um terminal. No entanto, o Terminal suporta uma extensão da sequência de escape ED (Apagar na Exibição) para apagar o deslocamento de retorno ESC [ 3 J. Você pode limpar a tela, então use isso, por exemplo,reset && printf '\e[3J’
Chris Page
Veja minha resposta aqui apple.stackexchange.com/a/113168/6883 para mais detalhes sobre a extensão Erase in Display.
Chris Page
@ ChrisPage: Eu percebo que terminais são coisas estranhas, mas se você se declarar como um xterm(através de TERM=xterm) eu esperaria que você emula um superconjunto do XTerm, que limpa o seu retrocesso na reinicialização. (Assim como se você mandasse a seqüência de escape para "blue", você esperaria azul.) Concedido, meu xterm me diz isso Erase is backspace., o que eu sou grato mais nada faz; isso é simplesmente chato.
Thanatos

Respostas:

10

Use $TERM_PROGRAM.

iTerm configura para iTerm.appe Terminal.app para Apple_Terminal.

Daniel Beck
fonte
Heh, OK, isso é claramente melhor do que o meu hack, +1 :). O hack deve funcionar para qualquer emulador de terminal, não apenas esses dois.
Terdon
Não há uma maneira única de detectar cada emulador de terminal. Para o xterm, você pode verificar a variável $ XTERM_VERSION, por exemplo. Isso vai cuidar de quais são provavelmente os três emuladores mais populares no OS X.
Chris Page
Aceitando isso, como é um bom começo. Infelizmente, isso não é tão fácil, já que esta variável não está disponível dentro de uma sessão SSH. Eu suspeito que existem configurações que eu possa editar para encaminhá-lo.
Thanatos
1
@Thanatos sshd_config's AcceptEnvprovavelmente. Como isso (seu shell é executado em um host diferente daquele em que o seu Terminal é executado) é uma informação muito importante, deve ser parte da questão.
Daniel Beck
@DanielBeck: Não é estritamente o caso; Eu gostaria de fazer o mesmo localmente e remotamente. O que eu estou indo é que digitar "reset" em um terminal provoca uma redefinição do terminal, não importa se estou no OS X ou Linux, trabalhando localmente ou remotamente. Eu editei isso na pergunta.
Thanatos
1

$TERMnão tem nada a ver com o emulador de terminal atualmente em execução, é apenas o seu terminal padrão e pode ser configurado para qualquer coisa. Para obter o nome do emulador de terminal que você está executando, você pode usar pspara obter o PID do processo pai do seu shell atual.

NOTA: O seguinte falhará no OSX, mas deverá funcionar bem no Linux

O PID do seu processo shell atual é $$. A partir daí, você pode usar pspara mostrar uma árvore de processos e imprimir o PID do pai da sua sessão atual do shell:

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

Você pode então passar esse PID para pse dizer para imprimir o nome do comando:

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

Isso vai truncar o nome, deve ser o suficiente para você descobrir, mas pode não ser bom para o script. Para obter o nome completo, você pode tentar

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

Isto é o que eu recebo no meu sistema usando alguns terminais 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
fonte
Não funciona no OS X:ps: illegal option -- f
Daniel Beck
@ DanielBeck darn estilo BSD, obrigado. Você poderia tentar novamente com a versão atualizada? Adicionar um -antes das opções deve funcionar de acordo com o OSX man ps.
Terdon
Melhor, mas ainda não está funcionando. O formato de saída é diferente (PID é $2, PPID é $3) e o processo pai do shell pode ser login(dependendo da configuração do Terminal), com parâmetros diferentes. No entanto, seu processo pai é Terminal. --no-headersnão existe, você precisaria de algo parecido tail -n1. E como todos os processos com interface do usuário têm um argumento-psn_0_... , awk '{print $NF}'também não funciona.
Daniel Beck
@DanielBeck bem shucks então. Ok, obrigado por esclarecer que isso falha no OSX.
Terdon
Note que isso só funciona localmente. Você não pode usar essa abordagem para descobrir qual emulador de terminal está sendo usado em um cliente remoto. A melhor resposta é procurar por variáveis ​​como $ TERM_PROGRAM (como mencionado na resposta de @ DanielBeck) e $ XTERM_VERSION para deduzir o aplicativo emulador.
Chris Página
0

Aqui está uma maneira portátil de obter o nome ou o caminho do processo pai:

iTerm 2:

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

gnome-terminal no Ubuntu:

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

Terminal.app:

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

Observe que, se Terminal.app estiver configurado para abrir novos shells com o shell de login padrão, o processo pai do shell será, logine não o terminal.

A commcoluna é o caminho completo do comando no OS X e o nome do comando truncado para 15 caracteres na implementação do procps no Linux.

Lri
fonte
Tentei em iTerm e tenho login- Eu personalizar meu perfil algum tempo atrás para executar o comando login -fp danielbeck?
Daniel Beck