Bash: So bestimmen Sie, ob das Terminal von einer Drittanbieter-App geöffnet wird

9

Ich möchte, dass mein Bash-Skript (speziell mein ~/.bashrc) nur dann etwas tut, wenn das Terminal direkt von mir geöffnet wurde, und etwas anderes, wenn es über eine App geöffnet wurde, z. B. VS-Code. Wie kann ich feststellen, was der Fall ist? Gibt es dafür eine Variable? Danke im Voraus.

Papiertüte
quelle
1
Es gibt einen Weg, meine erste Antwort wäre, mit dem zweiten Beispiel in askubuntu.com/a/1042727/295286 zu gehen . Versuchen Sie, VS zu öffnen, und führen Sie den envBefehl aus. Überprüfen Sie, ob es eine VS-spezifische Variable gibt, die wir verwenden können.
Sergiy Kolodyazhnyy
1
Wenn nichts vorhanden ist, versuchen Sie es umgekehrt: Überprüfen Sie, ob Ihr Terminalemulator eine Variable festlegt. Ich verwende yakuakeund habe einen Variablensatz PULSE_PROP_OVERRIDE_application.name=Yakuakeund xtermSätze XTERM_VERSION=XTerm(322)auf meinem Computer.
Dessert
@SergiyKolodyazhnyy Würden Sie bitte eine Antwort für den Ansatz der Umgebungsvariablen schreiben?
Dessert
@dessert würde ich, aber ich habe VS nicht installiert, weder OP hat geantwortet, wenn es eine bestimmte Umgebungsvariable gibt, an die wir uns binden können.
Sergiy Kolodyazhnyy
@SergiyKolodyazhnyy Ich auch nicht, aber der Fragentitel sagt App von Drittanbietern und ich nehme an, dass es genau wie jeder Terminalemulator funktioniert - ich denke, eine Antwort wie env >env_term1in einem Emulator, env >env_term2in einem zweiten und wie man das verwendet, was diff env_term{1,2}sagt, ist sehr nützlich. Immerhin sagt OP zB VS Code .
Dessert

Antworten:

10

Sie könnten es wahrscheinlich tun, indem Sie die Vorfahren der Shell zurückgehen und herausfinden, ob sie von etwas gestartet wurde, das "Ihnen" entspricht, oder von einem anderen Programm.

Rufen Sie die PID (Prozess-ID) der Shell und daraus die PPID (übergeordnete Prozess-ID) ab. Gehen Sie weiter, bis Sie zu etwas kommen, das Ihnen sagt, woher es kommt. Möglicherweise müssen Sie mit Ihrem System experimentieren - zumindest weiß ich nicht, ob es universell ist.

Holen Sie sich beispielsweise auf meinem System die PID einer Shell und pszeigen Sie damit an, dass es sich um Folgendes handelt bash:

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

Holen Sie sich die PPID von 18852:

$ ps -o ppid= -p 18852
18842

Finden Sie heraus, was die PPID (18842) ist:

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

Wir können sehen, dass es sich um ein Gnome-Terminal handelt, dh um das Terminal-Emulator- / Terminal-Fenster. Vielleicht ist das gut genug für Sie, wenn Ihre vom anderen Programm gestartete Shell nicht in einem Terminalemulatorfenster ausgeführt wird.

Wenn es nicht gut genug ist, gehe ein anderes Level hinauf:

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

Dies sagt uns, dass gnome-terminalvon gestartet wurde init. Ich vermute, dass Ihre Shell, die von einem anderen Programm gestartet wurde, dort etwas anderes haben wird.

Mark Smith
quelle
... oder vielleicht indem Sie das Ergebnis vonpstree -s $$
steeldriver
9
"Dies sagt uns, dass das Gnome-Terminal von init gestartet wurde." Ich finde es unwahrscheinlich, dass init Terminalfenster startet. Vielmehr starb alles, was mit dem Gnome-Terminal begann, und das Gnome-Terminal wurde erneut auf init übertragen. Beim Auschecken des Gnome-Terminals scheint es sich um Doppelgabeln zu handeln. Wenn es ausgeführt wird, gibt es sich zuerst selbst und beendet den ursprünglichen Prozess, wobei der neue fortgesetzt wird.
JoL
@JoL Fairer Punkt. Dieser initProzess ist jedoch nicht pid 1, nicht sicher, ob dies etwas ändern würde.
Kasperd
Vielen Dank! Ich konnte feststellen, dass weder VS Code noch Eclipse das Terminal als Kind von ausführen gnome-terminal. Ich habe meinen Befehl unter ausgeführt if [ $(pstree -s $$ | grep "gnome-terminal" -c) -gt 0 ]; then ...und es hat funktioniert.
PaperBag
9

Was Visual Studio Code betrifft, gibt es anscheinend eine Möglichkeit, zusätzliche Umgebungsvariablen für das integrierte Terminal festzulegen . Richten Sie Visual Studio für die Verwendung dieser Konfiguration ein:

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

Und innerhalb ~/.bashrc:

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

Im Allgemeinen können Sie sich auf die Umgebung verlassen, die dem bashProzess zugewiesen wurde. Zum Beispiel die $TERMVariable , und führen Sie einen ähnlichen if..then...else...fiZweig für [ "$TERM" = "xterm" ]oder etwas anderes aus. Von Fall zu Fall können Sie die Unterschiede in der Umgebung untersuchen env, indem Sie sie in jeder Konsole ausführen, diese in der Datei speichern, wie in env > output_console1.txtund diff output_console1.txt output_console2.txtwie vom Dessert in den Kommentaren vorgeschlagen .

Sergiy Kolodyazhnyy
quelle
$Env:varist nicht die Syntax für Umgebungsvariablen in Bash. Das sieht für mich wie eine Powershell-Sache aus.
Dietrich Epp
@DietrichEpp Ja, ich habe ursprünglich nach Möglichkeiten gesucht, zusätzliche Umgebungsvariablen in Visual Studio festzulegen, aber übersehen, dass die Antworten PowerShell verwenden. So $foogenügt. Kaffee ist wahrscheinlich nicht genug.
Sergiy Kolodyazhnyy
Für den allgemeinen Fall von Programmen von Drittanbietern ohne env-Einstellung können Sie vor dem Ausführen des Programms eine benutzerdefinierte env-Variable in einem Wrapper festlegen . Siehe meine Antwort .
Peter Cordes
2

Wenn Sie über eine bestimmte Drittanbieter-App sprechen, verwenden Sie eine Umgebungsvariable. Die meisten Programme werden die gesamte Umgebung unverändert weitergeben, wenn sie neue Prozesse fork + ausführen.

So starten Sie diese App mit einem benutzerdefinierten env var Sie überprüfen können . zB einen Alias ​​dafür erstellen alias vs=RUNNING_FROM_VSCODE=1 VSCodeoder ein Wrapper-Skript wie folgt erstellen:

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

Dann können Sie in Ihrem .bashrctun

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

Eine bash-arithmetische Anweisung (( ))ist wahr, wenn der Ausdruck eine Ganzzahl ungleich Null ergibt (weshalb ich 1oben verwendet habe). Die leere Zeichenfolge (für eine nicht gesetzte env var) ist false. Es ist gut für Boolesche Bash-Variablen, aber Sie können es genauso einfach truemit einem herkömmlichen POSIX verwenden und überprüfen

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

Wenn Ihre App die Umgebung für ihre untergeordneten Elemente größtenteils löscht , sie jedoch $PATHunverändert weitergibt, können Sie dies in Ihrem Wrapper verwenden:

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

und überprüfen Sie dies mit einem Pattern-Match wie Bash [[ "${PATH%RUNNING_FROM_VSCODE}" != "$PATH" ]], um zu überprüfen, ob das Entfernen eines Suffixes aus PATH es ändert.

Dies sollte harmlos eine zusätzliche Verzeichnissuche durchführen, wenn das Programm nach nicht gefundenen externen Befehlen sucht. /dev/nullist definitiv kein Verzeichnis auf einem System, daher ist es sicher, es als falsches Verzeichnis zu verwenden, das schnell dazu führt, ENOTDIRdass PATH-Suchen in früheren PATH-Einträgen nicht das finden, wonach sie suchen.

Peter Cordes
quelle
Wrapper-Skripte sind normalerweise ein sinnvoller Ansatz, daher +1. Der einzige kleine Nachteil ist, dass Sie bei 3 Programmen möglicherweise 3 Wrapper-Skripte oder ein Wrapper-Skript mit 3 verschiedenen Argumenten haben möchten, was es mühsam machen kann. Trotzdem ist es ein solider Ansatz.
Sergiy Kolodyazhnyy
1

Hier sind meine 2 Cent. Fügen Sie es einfach zu Ihrem hinzu .bashrc. Ersetzen Sie terminalsdurch Ihre bevorzugten Terminals und exportbefehlen Sie durch Ihre.

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
quelle
Dies würde mit dem Server-Client-Modell von gnome-terminal nicht funktionieren.
Egmont