Bash: come determinare se il terminale è aperto da un'app di terze parti


9

Voglio che il mio script bash (in particolare il mio ~/.bashrc) faccia qualcosa solo se il terminale è stato aperto direttamente da me e faccio qualcos'altro se è stato aperto tramite un'app, ad esempio VS Code. Come posso determinare qual è il caso? C'è una variabile per quello? Grazie in anticipo.


1
C'è una specie di modo, la mia prima risposta sarebbe quella di andare con il secondo esempio in askubuntu.com/a/1042727/295286 . Prova ad aprire VS ed esegui il envcomando. Verifica se esiste una variabile specifica VS che possiamo usare.
Sergiy Kolodyazhnyy,

1
Se non c'è nulla, provalo al contrario: verifica se l'emulatore di terminale imposta una variabile. Uso yakuakee ho un PULSE_PROP_OVERRIDE_application.name=Yakuakeset di variabili e xtermset XTERM_VERSION=XTerm(322)sulla mia macchina.
dessert

@SergiyKolodyazhnyy Scriveresti una risposta per l'approccio delle variabili d'ambiente, per favore?
dessert

@dessert Lo farei, ma non ho VS installato, né OP ha risposto se esiste una particolare variabile d'ambiente su cui possiamo aggrapparci.
Sergiy Kolodyazhnyy,

@SergiyKolodyazhnyy Nemmeno io, ma il titolo della domanda dice un'app di terze parti e suppongo che funzioni esattamente come qualsiasi emulatore di terminale - Penso che una risposta come env >env_term1in un emulatore, env >env_term2in un secondo e come usare ciò che diff env_term{1,2}dice sia molto utile. Dopo tutto, OP dice ad es. VS Code .
dessert

Risposte:


10

Probabilmente potresti farlo risalendo gli antenati della shell e scoprendo se è stato avviato da qualcosa che equivale a "te" o ad un altro programma.

Ottieni il PID della shell (ID processo) e da ciò il suo PPID (ID processo padre). Continuate a salire fino ad arrivare a qualcosa che vi dice da dove proviene. Potrebbe essere necessario sperimentare sul tuo sistema - almeno, non so se sarà universale.

Ad esempio, sul mio sistema, ottieni il PID di una shell e usa psper mostrare che è bash:

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

Ottieni il PPID del 18852:

$ ps -o ppid= -p 18852
18842

Scopri cos'è il PPID (18842):

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

Possiamo vedere che è gnome-terminal, cioè l'emulatore di terminale / finestra del terminale. Forse è abbastanza buono per te, se la tua shell lanciata dall'altro programma non è in esecuzione in una finestra dell'emulatore di terminale.

Se non è abbastanza buono, sali di un altro livello:

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

Questo ci dice che è gnome-terminalstato avviato da init. Sospetto che la tua shell avviata da un altro programma avrà qualcosa di diverso lì.


... o forse risalendo il risultato dipstree -s $$
steeldriver,

9
"Questo ci dice che gnome-terminal è stato avviato da init" Trovo improbabile che init avvii le finestre del terminale. Piuttosto, qualunque cosa abbia iniziato gnome-terminal è morta, e gnome-terminal è stato ri-genitoriale in init. Controllando gnome-terminal, sembra che abbia una doppia forcella. Quindi, quando viene eseguito, si forcella dapprima e uccide il processo originale, continuando con quello nuovo.
JoL

@JoL Fair point. initTuttavia, questo processo non è pid 1, non sono sicuro che cambierebbe qualcosa.
Kasperd,

Molte grazie! Sono stato in grado di rilevare che né VS Code né Eclipse eseguono il terminale come figlio di gnome-terminal. Ho eseguito il mio comando sotto if [ $(pstree -s $$ | grep "gnome-terminal" -c) -gt 0 ]; then ...e ha funzionato.
PaperBag,

9

Per quanto riguarda Visual Studio Code, a quanto pare esiste un modo per impostare variabili di ambiente aggiuntive per il terminale integrato . Quindi, imposta Visual Studio per utilizzare questa configurazione:

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

E entro ~/.bashrc:

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

In generale, è possibile fare affidamento sull'ambiente dato al bashprocesso. Ad esempio, la $TERMvariabile ed esegui un if..then...else...firamo simile per [ "$TERM" = "xterm" ]o qualcos'altro. Su base caso per caso, è possibile esaminare le differenze nell'ambiente eseguendo envin ciascuna console, salvarlo su file come in env > output_console1.txte diff output_console1.txt output_console2.txtcome suggerito da dessert nei commenti .


$Env:varnon è la sintassi per le variabili di ambiente in Bash. Questa mi sembra una cosa di Powershell.
Dietrich Epp,

@DietrichEpp Sì, inizialmente stavo cercando i modi per impostare variabili di ambiente aggiuntive in Visual Studio, ma ho trascurato che le risposte stavano usando PowerShell. Quindi $fooè abbastanza. Il caffè probabilmente non è abbastanza.
Sergiy Kolodyazhnyy il

Nel caso generale di programmi di terze parti che non dispongono di impostazioni env, è possibile impostare una var env personalizzata in un wrapper prima di eseguire il programma. Vedere la mia risposta .
Peter Cordes,

2

Se stai parlando di un'app di terze parti specifica, utilizza una variabile di ambiente. La maggior parte dei programmi passerà invariato nell'intero ambiente quando eseguono il fork + eseguono nuovi processi.

Quindi, avvia questa app con un ambiente personalizzato che puoi verificare . ad esempio crea un alias come tale alias vs=RUNNING_FROM_VSCODE=1 VSCodeo crea uno script wrapper come questo:

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

Quindi nel tuo .bashrc, puoi farlo

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

Un'istruzione aritmetica bash (( ))è vera se l'espressione restituisce un numero intero diverso da zero (motivo per cui ho usato 1sopra). La stringa vuota (per un env var non impostato) è falsa. È utile per le variabili booleane bash, ma puoi anche usarlo truee controllarlo con un POSIX tradizionale

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

Se la tua app cancella l'ambiente per i suoi figli , ma continua a rimanere $PATHinvariata, puoi utilizzarla nel tuo wrapper:

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

e controllalo con un pattern-match come bash [[ "${PATH%RUNNING_FROM_VSCODE}" != "$PATH" ]]per verificare se lo stripping di un suffisso da PATH lo modifica.

Questo dovrebbe fare innocuamente una ricerca di directory extra quando il programma cerca comandi esterni non trovati. /dev/nullnon è sicuramente una directory su nessun sistema, quindi è sicuro da usare come una directory fasulla che si tradurrà rapidamente ENOTDIRse le ricerche PATH non trovano ciò che stanno cercando nelle voci PATH precedenti.


Gli script wrapper sono generalmente un approccio sensato, quindi +1. L'unico svantaggio minore è che se hai 3 programmi, potresti voler avere 3 script wrapper o uno script wrapper che prendono 3 argomenti diversi, il che può renderlo noioso. Tuttavia è un approccio solido.
Sergiy Kolodyazhnyy il

1

Ecco i miei 2 centesimi. Aggiungilo al tuo .bashrc. Sostituisci terminalscon i tuoi terminali preferiti e exportordina con i tuoi.

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

Questo non funzionerebbe con il modello server-client di gnome-terminal.
egmont,
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.