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.


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.


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
    

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.


Tentei em iTerm e tenho login- Eu personalizar meu perfil algum tempo atrás para executar o comando login -fp danielbeck?
— Daniel Beck
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.