Bash: cómo determinar si la aplicación de terceros abre el terminal

9

Quiero que mi script bash (específicamente mi ~/.bashrc) haga algo solo si abrí el terminal directamente, y que haga algo más si se abrió a través de una aplicación, por ejemplo, VS Code. ¿Cómo puedo determinar cuál es el caso? ¿Hay una variable para eso? Gracias por adelantado.

Bolsa de papel
fuente
1
De alguna manera, mi primera respuesta sería ir con el segundo ejemplo en askubuntu.com/a/1042727/295286 . Intenta abrir VS y ejecuta el envcomando. Vea si hay una variable específica de VS que podamos usar.
Sergiy Kolodyazhnyy
1
Si no hay nada, pruébelo al revés: vea si su emulador de terminal establece una variable. Yo uso yakuakey tengo un PULSE_PROP_OVERRIDE_application.name=Yakuakeconjunto variable , y xtermconjuntos XTERM_VERSION=XTerm(322)en mi máquina.
postre
@SergiyKolodyazhnyy ¿Podría escribir una respuesta para el enfoque de variable de entorno, por favor?
postre
@dessert lo haría, pero no tengo VS instalado, ni OP ha respondido si hay alguna variable de entorno particular en la que podamos fijarnos.
Sergiy Kolodyazhnyy
@SergiyKolodyazhnyy Yo tampoco, pero el título de la pregunta dice aplicación de terceros y supongo que funciona como cualquier emulador de terminal: creo que una respuesta como env >env_term1en un emulador, env >env_term2en un segundo y cómo usar lo que diff env_term{1,2}dice es muy útil. Después de todo, OP dice, por ejemplo, VS Code .
postre

Respuestas:

10

Probablemente podría hacerlo caminando de regreso a la ascendencia del shell y averiguando si fue iniciado por algo que equivale a "usted" u otro programa.

Obtenga el PID del shell (ID del proceso), y de ahí su PPID (ID del proceso padre). Sigue subiendo hasta llegar a algo que te diga de dónde vino. Es posible que deba experimentar en su sistema; al menos, no sé si será universal.

Por ejemplo, en mi sistema, obtenga el PID de un shell y úselo pspara mostrar que es bash:

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

Obtenga el PPID de 18852:

$ ps -o ppid= -p 18852
18842

Descubra cuál es el PPID (18842):

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

Podemos ver que es gnome-terminal, es decir, el emulador de terminal / ventana de terminal. Tal vez eso sea lo suficientemente bueno para usted, si su shell lanzado por el otro programa no se ejecuta en una ventana de emulador de terminal.

Si no es lo suficientemente bueno, sube otro nivel:

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

Esto nos dice que gnome-terminalfue iniciado por init. Sospecho que su shell iniciado por otro programa tendrá algo diferente allí.

Mark Smith
fuente
... o quizás subiendo el resultado depstree -s $$
steeldriver
99
"Esto nos dice que gnome-terminal fue iniciado por init" Me parece poco probable que init inicie la ventana de terminal. Más bien, lo que comenzó gnome-terminal murió, y gnome-terminal se volvió a criar en init. Al revisar la terminal gnome, parece que se bifurca dos veces. Entonces, cuando se ejecuta, primero se bifurca y mata el proceso original, continuando en el nuevo.
JoL
@JoL Punto justo. Sin initembargo, ese proceso no es pid 1, no estoy seguro de si eso cambiaría algo.
kasperd
¡Muchas gracias! Pude detectar que ni VS Code ni Eclipse ejecutan el terminal como hijo de gnome-terminal. Ejecuté mi comando bajo if [ $(pstree -s $$ | grep "gnome-terminal" -c) -gt 0 ]; then ...y funcionó.
PaperBag
9

En lo que respecta a Visual Studio Code, aparentemente hay una manera de establecer variables de entorno adicionales para el terminal integrado . Entonces, configure Visual Studio para usar esta configuración:

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

Y dentro de ~/.bashrc:

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

En general, puede confiar en el entorno dado al bashproceso. Por ejemplo, la $TERMvariable , y ejecuta una if..then...else...firama similar para [ "$TERM" = "xterm" ]o algo más. En cada caso, puede investigar las diferencias en el entorno mediante la ejecución enven cada consola, guardarlo en el archivo como en env > output_console1.txt, y diff output_console1.txt output_console2.txtcomo sugiere el postre en los comentarios .

Sergiy Kolodyazhnyy
fuente
$Env:varno es la sintaxis para las variables de entorno en Bash. Esto me parece una cosa de Powershell.
Dietrich Epp
@DietrichEpp Sí, originalmente estaba investigando las formas de establecer variables de entorno adicionales en Visual Studio, pero pasé por alto que las respuestas estaban usando PowerShell. Entonces $fooes suficiente. El café probablemente no es suficiente.
Sergiy Kolodyazhnyy
Para el caso general de los programas de terceros que no tienen la configuración de env, puede configurar una var de env personalizada en un contenedor antes de ejecutar el programa. Mira mi respuesta .
Peter Cordes
2

Si está hablando de una aplicación de terceros específica, use una variable de entorno. La mayoría de los programas pasarán todo el entorno sin cambios cuando bifurcan + ejecutan nuevos procesos.

Entonces, inicie esta aplicación con un entorno personalizado que puede verificar . Por ejemplo, crea un alias para él alias vs=RUNNING_FROM_VSCODE=1 VSCodeo crea un script de envoltura como este:

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

Entonces en tu .bashrc, puedes hacer

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

Una declaración aritmética bash (( ))es verdadera si la expresión se evalúa como un número entero distinto de cero (que es la razón por la que usé 1anteriormente). La cadena vacía (para una variable de entorno no establecida) es falsa. Es bueno para las variables booleanas bash, pero podría usarlo truey verificarlo fácilmente con un POSIX tradicional

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

Si su aplicación limpia principalmente el entorno para sus hijos , pero sigue $PATHsin cambios, puede usar esto en su contenedor:

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

y verifíquelo con un patrón de coincidencia como bash [[ "${PATH%RUNNING_FROM_VSCODE}" != "$PATH" ]]para verificar si quitar un sufijo de PATH lo cambia.

Esto debería hacer inofensivamente una búsqueda de directorio adicional cuando el programa busca comandos externos no encontrados. /dev/nulldefinitivamente no es un directorio en ningún sistema, por lo que es seguro usarlo como un directorio falso que resultará rápidamente ENOTDIRsi las búsquedas PATH no encuentran lo que están buscando en las entradas PATH anteriores.

Peter Cordes
fuente
Los guiones de envoltura suelen ser un enfoque razonable, por lo tanto, +1 La única desventaja menor es que si tiene 3 programas, es posible que desee tener 3 scripts de contenedor o un script de contenedor que tome 3 argumentos diferentes, lo que puede hacer que sea tedioso. Sin embargo, es un enfoque sólido.
Sergiy Kolodyazhnyy
1

Aquí están mis 2 centavos. Solo agrégalo a tu .bashrc. Reemplace terminalscon sus terminales favoritas y exportordene con las suyas.

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
fuente
Esto no funcionaría con el modelo servidor-cliente de gnome-terminal.
egmont