Bash: comment déterminer si le terminal est ouvert par une application tierce

9

Je veux que mon script bash (spécifiquement le mien ~/.bashrc) ne fasse quelque chose que si le terminal a été ouvert par moi directement, et fasse autre chose s'il a été ouvert via une application, par exemple VS Code. Comment puis-je déterminer quel est le cas? Y a-t-il une variable pour cela? Merci d'avance.

Sac en papier
la source
1
Il y a en quelque sorte un moyen, ma première réponse serait d'aller avec le deuxième exemple dans askubuntu.com/a/1042727/295286 . Essayez d'ouvrir VS et d'exécuter la envcommande. Voyez s'il y a une variable spécifique à VS que nous pouvons utiliser.
Sergiy Kolodyazhnyy
1
S'il n'y a rien, essayez-le dans l'autre sens: voyez si votre émulateur de terminal définit une variable. J'utilise yakuakeet j'ai un PULSE_PROP_OVERRIDE_application.name=Yakuakeensemble de variables et des xtermensembles XTERM_VERSION=XTerm(322)sur ma machine.
dessert
@SergiyKolodyazhnyy Pourriez-vous écrire une réponse pour l'approche des variables d'environnement s'il vous plaît?
dessert
@dessert Je le ferais, mais je n'ai pas VS installé, ni OP n'a répondu s'il y a une variable d'environnement particulière sur laquelle nous pouvons nous accrocher.
Sergiy Kolodyazhnyy
@SergiyKolodyazhnyy Moi non plus, mais le titre de la question dit application tierce et je suppose que cela fonctionne comme n'importe quel émulateur de terminal - je pense qu'une réponse comme env >env_term1dans un émulateur, env >env_term2dans un second et comment utiliser ce qui diff env_term{1,2}est dit est très utile. Après tout, OP dit par exemple VS Code .
dessert

Réponses:

10

Vous pourriez probablement le faire en remontant l'ascendance du shell et en déterminant s'il a été démarré par quelque chose qui équivaut à «vous» ou un autre programme.

Obtenez le PID du shell (ID de processus), et de là son PPID (ID de processus parent). Continuez à monter jusqu'à ce que vous arriviez à quelque chose qui vous indique d'où il vient. Vous devrez peut-être expérimenter sur votre système - au moins, je ne sais pas si ce sera universel.

Par exemple, sur mon système, obtenez le PID d'un shell et utilisez pspour montrer que c'est bash:

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

Obtenez le PPID de 18852:

$ ps -o ppid= -p 18852
18842

Découvrez ce qu'est le PPID (18842):

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

Nous pouvons voir que c'est gnome-terminal, c'est-à-dire l'émulateur de terminal / fenêtre de terminal. C'est peut-être suffisant pour vous, si votre shell lancé par l'autre programme ne fonctionne pas dans une fenêtre d'émulateur de terminal.

Si ce n'est pas assez bon, montez d'un autre niveau:

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

Cela nous dit que cela gnome-terminala commencé par init. Je soupçonne que votre shell lancé par un autre programme aura quelque chose de différent là-bas.

Mark Smith
la source
... ou peut-être en remontant le résultat depstree -s $$
steeldriver
9
"Cela nous indique que gnome-terminal a été démarré par init" Je trouve peu probable que init démarre les fenêtres de terminal. Au lieu de cela, tout ce qui a commencé gnome-terminal est mort, et gnome-terminal a été re-parenté pour init. En vérifiant gnome-terminal, il semble que ce soit une double fourche. Donc, quand il s'exécute, il se bifurque d'abord et tue le processus d'origine, en continuant dans le nouveau.
JoL
@JoL Fair point. Ce initprocessus n'est cependant pas pid 1, je ne sais pas si cela changerait quelque chose.
kasperd
Merci beaucoup! J'ai pu détecter que ni VS Code ni Eclipse n'exécutaient le terminal en tant qu'enfant de gnome-terminal. J'ai exécuté ma commande sous if [ $(pstree -s $$ | grep "gnome-terminal" -c) -gt 0 ]; then ...et cela a fonctionné.
PaperBag
9

En ce qui concerne Visual Studio Code, il existe apparemment un moyen de définir des variables d'environnement supplémentaires pour le terminal intégré . Donc, configurez Visual Studio pour utiliser cette configuration:

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

Et dans ~/.bashrc:

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

En général, vous pouvez vous fier à l'environnement donné au bashprocessus. Par exemple, la $TERMvariable , et exécutez une if..then...else...fibranche similaire pour [ "$TERM" = "xterm" ]ou autre chose. Au cas par cas, vous pouvez étudier les différences dans l'environnement via l'exécution envdans chaque console, l'enregistrer dans un fichier comme dans env > output_console1.txtet diff output_console1.txt output_console2.txtcomme suggéré par dessert dans les commentaires .

Sergiy Kolodyazhnyy
la source
$Env:varn'est pas la syntaxe des variables d'environnement dans Bash. Cela ressemble à une chose Powershell pour moi.
Dietrich Epp
@DietrichEpp Oui, à l'origine, je cherchais les moyens de définir des variables d'environnement supplémentaires dans Visual Studio, mais j'ai ignoré que les réponses utilisaient PowerShell. C'est $fooassez. Le café ne suffit probablement pas.
Sergiy Kolodyazhnyy
Pour le cas général des programmes tiers qui n'ont pas de paramètre env, vous pouvez définir une variable env personnalisée dans un wrapper avant d' exécuter le programme. Voir ma réponse .
Peter Cordes
2

Si vous parlez d'une application tierce spécifique, utilisez une variable d'environnement. La plupart des programmes transmettront l’environnement entier inchangé lorsqu’ils forkent + exécutent de nouveaux processus.

Alors, démarrez cette application avec une var env personnalisée que vous pouvez vérifier . par exemple, créez un alias pour celui-ci alias vs=RUNNING_FROM_VSCODE=1 VSCode, ou créez un script wrapper comme ceci:

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

Ensuite, dans votre .bashrc, vous pouvez faire

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

Une instruction arithmétique bash (( ))est vraie si l'expression est évaluée à un entier non nul (c'est pourquoi j'ai utilisé 1ci-dessus). La chaîne vide (pour une variable env non définie) est fausse. C'est bien pour les variables booléennes bash, mais vous pouvez tout aussi bien l'utiliser trueet le vérifier avec un POSIX traditionnel

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

Si votre application efface principalement l'environnement pour ses enfants , mais passe toujours $PATHinchangée, vous pouvez utiliser ceci dans votre wrapper:

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

et vérifiez-le avec un pattern-match comme bash [[ "${PATH%RUNNING_FROM_VSCODE}" != "$PATH" ]]pour vérifier si la suppression d'un suffixe de PATH le modifie.

Cela devrait sans danger faire une recherche de répertoire supplémentaire lorsque le programme recherche des commandes externes introuvables. /dev/nulln'est certainement pas un répertoire sur aucun système, il est donc sûr de l'utiliser comme un faux répertoire qui se traduira rapidement ENOTDIRsi les recherches PATH ne trouvent pas ce qu'elles recherchent dans les entrées PATH antérieures.

Peter Cordes
la source
Les scripts Wrapper sont généralement une approche sensée, d'où +1. Le seul inconvénient mineur est que si vous avez 3 programmes, vous voudrez peut-être avoir 3 scripts wrapper ou un script wrapper prenant 3 arguments différents, ce qui peut être fastidieux. Néanmoins, c'est une approche solide.
Sergiy Kolodyazhnyy
1

Voici mes 2 cents. Ajoutez-le simplement à votre .bashrc. Remplacez terminalspar vos terminaux préférés et exportcommandez avec les vôtres.

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
la source
Cela ne fonctionnerait pas avec le modèle serveur-client de gnome-terminal.
egmont