Bash: como determinar se o terminal é aberto por um aplicativo de terceiros

9

Eu quero que meu script bash (especificamente o meu ~/.bashrc) faça algo somente se o terminal foi aberto diretamente por mim e faça outra coisa se ele foi aberto através de um aplicativo, por exemplo, VS Code. Como posso determinar qual é o caso? Existe uma variável para isso? Desde já, obrigado.

Saco de papel
fonte
11
Existe uma maneira, minha primeira resposta seria ir com o segundo exemplo em askubuntu.com/a/1042727/295286 . Tente abrir o VS e execute o envcomando. Veja se existe uma variável específica do VS que possamos usar.
Sergiy Kolodyazhnyy
11
Se não houver nada, tente o contrário: Veja se o emulador de terminal define uma variável. Eu uso yakuakee tenho um PULSE_PROP_OVERRIDE_application.name=Yakuakeconjunto de variáveis e xtermconjuntos XTERM_VERSION=XTerm(322)na minha máquina.
dessert
@SergiyKolodyazhnyy Você poderia escrever uma resposta para a abordagem de variáveis ​​de ambiente, por favor?
dessert
@dessert Gostaria, mas não tenho o VS instalado, nem o OP respondeu se houver alguma variável de ambiente específica na qual possamos nos agarrar.
Sergiy Kolodyazhnyy
@SergiyKolodyazhnyy Nem eu, mas o título da pergunta diz aplicativo de terceiros e acho que funciona como qualquer emulador de terminal - acho que uma resposta como env >env_term1em um emulador, env >env_term2em um segundo e como usar o que diff env_term{1,2}diz é muito útil. Afinal, OP diz ex Código VS .
dessert

Respostas:

10

Você provavelmente poderia fazer isso retornando à ancestralidade do shell e calculando se foi iniciado por algo que equivale a "você" ou outro programa.

Obtenha o PID (ID do processo) do shell e, a partir dele, o PPID (ID do processo pai). Continue subindo até chegar a algo que lhe diga de onde veio. Você pode precisar experimentar no seu sistema - pelo menos, não sei se será universal.

Por exemplo, no meu sistema, obtenha o PID de um shell e use pspara mostrar que é bash:

$ echo $$
18852
$ ps --pid 18852
  PID TTY          TIME CMD
18852 pts/1    00:00:00 bash

Obtenha o PPID do 18852:

$ ps -o ppid= -p 18852
18842

Descubra o que é o PPID (18842):

$ ps --pid 18842
  PID TTY          TIME CMD
18842 ?        00:00:02 gnome-terminal

Podemos ver que é o gnome-terminal, ou seja, o emulador / janela do terminal. Talvez isso seja bom o suficiente para você, se o seu shell iniciado por outro programa não estiver sendo executado em uma janela do emulador de terminal.

Se não for bom o suficiente, suba outro nível:

$ ps -o ppid= -p 18842
 2313
$ ps --pid 2313
  PID TTY          TIME CMD
 2313 ?        00:00:00 init

Isso nos diz que gnome-terminalfoi iniciado por init. Eu suspeito que seu shell iniciado por outro programa terá algo diferente lá.

Mark Smith
fonte
... ou talvez a pé até o resultado depstree -s $$
steeldriver
9
"Isso nos diz que o gnome-terminal foi iniciado pelo init" Acho improvável que o init inicie as janelas do terminal. Em vez disso, o que quer que tenha iniciado o gnome-terminal morreu e o gnome-terminal foi re-criado para iniciar. Verificando o terminal gnome, parece que há garfos duplos. Portanto, quando é executado, primeiro se bifurca e mata o processo original, continuando no novo.
JOL
@JoL Fair point. Esse initprocesso não é o pid 1, porém, não tenho certeza se isso mudaria alguma coisa.
kasperd
Muito obrigado! Pude detectar que nem o VS Code nem o Eclipse executam o terminal como filho de gnome-terminal. Eu executei meu comando if [ $(pstree -s $$ | grep "gnome-terminal" -c) -gt 0 ]; then ...e funcionou.
precisa saber é o seguinte
9

No que diz respeito ao Visual Studio Code, aparentemente existe uma maneira de definir variáveis ​​de ambiente adicionais para o terminal integrado . Portanto, configure o Visual Studio para usar esta configuração:

"terminal.integrated.env.linux": {
  "visual_studio": "true"
}

E dentro de ~/.bashrc:

if [ -n "$visual_studio" ]; then
    # do something for Visual Studio
else
    # do something else for other types of terminal
fi

Em geral, você pode confiar no ambiente dado ao bashprocesso. Por exemplo, a $TERMvariável e execute uma if..then...else...firamificação semelhante para [ "$TERM" = "xterm" ]ou qualquer outra coisa. Caso a caso, você pode investigar as diferenças no ambiente executando envem cada console, salvá-lo no arquivo como em env > output_console1.txte diff output_console1.txt output_console2.txtconforme sugerido pela sobremesa nos comentários .

Sergiy Kolodyazhnyy
fonte
$Env:varnão é a sintaxe para variáveis ​​de ambiente no Bash. Isso me parece uma coisa do PowerShell.
Dietrich Epp
@DietrichEpp Sim, originalmente eu estava pesquisando maneiras de definir variáveis ​​de ambiente adicionais no Visual Studio, mas esqueci que as respostas estavam usando o PowerShell. Então $fooé o suficiente. Café provavelmente não é suficiente.
Sergiy Kolodyazhnyy
Para o caso geral de programas de terceiros que não possuem configuração de ambiente, você pode definir um env var personalizado em um wrapper antes de executar o programa. Veja minha resposta .
Peter Cordes
2

Se você estiver falando de um aplicativo de terceiros específico, use uma variável de ambiente. A maioria dos programas passa por todo o ambiente inalterado quando eles executam novos processos.

Portanto, inicie este aplicativo com uma var env personalizada que você pode verificar . por exemplo, crie um alias para isso alias vs=RUNNING_FROM_VSCODE=1 VSCodeou crie um script de wrapper como este:

#!/bin/sh
export RUNNING_FROM_VSCODE=1
exec VSCode "$@"

Então no seu .bashrc, você pode fazer

if (($RUNNING_FROM_VSCODE)); then
   echo "started from inside VSCode"
   # RUNNING_FROM_VSCODE=0  # optional if you only want the immediate child
fi

Uma declaração aritmética bash (( ))é verdadeira se a expressão for avaliada como um número inteiro diferente de zero (razão pela qual usei 1acima). A cadeia vazia (para um env var não definido) é falsa. É bom para variáveis ​​booleanas do bash, mas você pode facilmente usá-lo truee procurá-lo com um POSIX tradicional

if [ "x$RUNNING_FROM_VSCODE" = "xtrue" ]; then
   echo "started from inside VSCode"
fi

Se seu aplicativo limpa principalmente o ambiente para seus filhos , mas ainda passa $PATHinalterado, você pode usá-lo no seu wrapper:

#!/bin/sh
export PATH="$PATH:/dev/null/RUNNING_FROM_VSCODE"
exec VSCode "$@"

e verifique-o com uma correspondência de padrão como o bash [[ "${PATH%RUNNING_FROM_VSCODE}" != "$PATH" ]]para verificar se a remoção de um sufixo do PATH o altera.

Isso deve fazer uma pesquisa extra de diretório inofensivamente quando o programa estiver procurando por comandos externos não encontrados. /dev/nulldefinitivamente não é um diretório em nenhum sistema, por isso é seguro usá-lo como um diretório falso que resultará rapidamente ENOTDIRse as pesquisas PATH não encontrarem o que estão procurando nas entradas PATH anteriores.

Peter Cordes
fonte
Os scripts de wrapper geralmente são uma abordagem sensata, portanto +1. A única desvantagem menor é que, se você tiver 3 programas, convém ter 3 scripts de wrapper ou um script de wrapper com 3 argumentos diferentes, o que pode torná-lo tedioso. No entanto, é uma abordagem sólida.
Sergiy Kolodyazhnyy
1

Aqui estão meus 2 centavos. Basta adicioná-lo ao seu .bashrc. Substitua terminalspor seus terminais favoritos e exportcomande pelos seus.

run_in_terminal(){
  local parent_command="$(ps --no-headers --pid $PPID -o command | awk '{print $1;}')"
  local parent="$(basename $parent_command)"
  local terminals=( gnome-terminal st xterm ) # list your favorite terminal here
  if [[ ${terminals[*]} =~ ${parent} ]]; then
    # Your commands to run if in terminal
    export MY_VAR_IN_TERMINAL="test"
  fi
}
run_in_terminal
Zalatik
fonte
Isso não funcionaria com o modelo servidor-cliente do gnome-terminal.
Egmont