Bash: Jak ustalić, czy terminal jest otwierany przez aplikację innej firmy

9

Chcę, aby mój skrypt bash (konkretnie mój ~/.bashrc) zrobił coś tylko wtedy, gdy terminal został otwarty przeze mnie bezpośrednio, i zrobiłbym coś innego, jeśli został otwarty za pośrednictwem aplikacji, np. VS Code. Jak mogę ustalić, co się dzieje? Czy jest na to zmienna? Z góry dziękuję.

Papierowa torba
źródło
1
Jest pewien sposób, moją pierwszą odpowiedzią byłoby pójście z drugim przykładem w askubuntu.com/a/1042727/295286 . Spróbuj otworzyć VS i uruchom envpolecenie. Sprawdź, czy istnieje zmienna specyficzna dla VS, której możemy użyć.
Sergiy Kolodyazhnyy
1
Jeśli nie ma nic, spróbuj na odwrót: Sprawdź, czy emulator terminala ustawia zmienną. Używam yakuakei mam PULSE_PROP_OVERRIDE_application.name=Yakuakezestaw zmiennych i xtermzestawów XTERM_VERSION=XTerm(322)na moim komputerze.
deser
@SergiyKolodyazhnyy Czy mógłbyś napisać odpowiedź na podejście oparte na zmiennej środowiskowej?
deser
@dessert Chciałbym, ale nie mam zainstalowanego VS, żaden OP nie odpowiedział, jeśli istnieje jakaś konkretna zmienna środowiskowa, na której możemy się zatrzasnąć.
Sergiy Kolodyazhnyy
@SergiyKolodyazhnyy Ja też nie, ale tytuł pytania brzmi : aplikacja innej firmy i przypuszczam, że działa ona tak jak każdy emulator terminala - myślę, że odpowiedź jak env >env_term1w jednym emulatorze, env >env_term2w drugim i jak używać tego diff env_term{1,2}, co mówi, jest bardzo przydatna. W końcu OP mówi np . Kod VS.
deser

Odpowiedzi:

10

Prawdopodobnie możesz to zrobić, wracając do przodków powłoki i sprawdzając, czy została ona uruchomiona przez coś, co jest równoznaczne z „tobą”, czy innym programem.

Uzyskaj PID powłoki (identyfikator procesu), a następnie jego PPID (identyfikator procesu nadrzędnego). Idź dalej, aż dojdziesz do czegoś, co powie ci, skąd to się wzięło. Być może będziesz musiał poeksperymentować na swoim systemie - przynajmniej nie wiem, czy będzie uniwersalny.

Na przykład w moim systemie pobierz PID powłoki i użyj, psaby pokazać, że bash:

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

Uzyskaj PPID z 18852:

$ ps -o ppid= -p 18852
18842

Dowiedz się, czym jest PPID (18842):

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

Widzimy, że jest to terminal gnome, tj. Emulator terminala / okno terminala. Może to ci wystarczy, jeśli twoja powłoka uruchomiona przez inny program nie działa w oknie emulatora terminala.

Jeśli to nie wystarczy, przejdź na wyższy poziom:

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

To mówi nam, że gnome-terminalzaczął init. Podejrzewam, że twoja powłoka uruchomiona przez inny program będzie miała tam coś innego.

Mark Smith
źródło
... lub może podchodząc do wynikupstree -s $$
steeldriver
9
„To mówi nam, że gnome-terminal został uruchomiony przez init”. Uważam, że mało prawdopodobne jest, aby init uruchomił okna terminalu. Raczej wszystko, co zaczęło się od gnome-terminalu, umarło, a gnome-terminal został ponownie rodzicielski do init. Sprawdzając terminal gnome, wydaje się, że rozwidla się podwójnie. Kiedy więc się uruchomi, najpierw rozwidla się i zabija pierwotny proces, kontynuując w nowym.
JoL
@JoL Fair point. Ten initproces nie jest jednak pid 1, nie jestem pewien, czy to cokolwiek zmieni.
kasperd
Wielkie dzięki! Byłem w stanie wykryć, że ani VS Code, ani Eclipse nie uruchamiają terminala jako dziecko gnome-terminal. Wykonałem swoje polecenie pod dowództwem if [ $(pstree -s $$ | grep "gnome-terminal" -c) -gt 0 ]; then ...i zadziałało.
PaperBag
9

Jeśli chodzi o Visual Studio Code, najwyraźniej istnieje sposób na ustawienie dodatkowych zmiennych środowiskowych dla zintegrowanego terminala . Więc skonfiguruj Visual Studio, aby używał tej konfiguracji:

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

I w ciągu ~/.bashrc:

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

Ogólnie można polegać na środowisku danego bashprocesu. Na przykład, w $TERMzmiennej i uruchomić podobny if..then...else...fioddział dla [ "$TERM" = "xterm" ]lub coś innego. W zależności od przypadku możesz zbadać różnice w środowisku, uruchamiając je envw każdej konsoli, zapisz to w pliku jak w pliku env > output_console1.txti diff output_console1.txt output_console2.txtzgodnie z sugestią deseru w komentarzach .

Sergiy Kolodyazhnyy
źródło
$Env:varnie jest składnią zmiennych środowiskowych w Bash. Dla mnie to wygląda jak PowerShell.
Dietrich Epp
@DietrichEpp Tak, pierwotnie szukałem sposobów na ustawienie dodatkowych zmiennych środowiskowych w Visual Studio, ale przeoczyłem, że odpowiedzi używały PowerShell. To $foowystarczy. Kawa prawdopodobnie nie wystarczy.
Sergiy Kolodyazhnyy
W ogólnym przypadku programów innych firm, które nie mają ustawienia env, przed uruchomieniem programu można ustawić niestandardową zmienną env var w opakowaniu . Zobacz moją odpowiedź .
Peter Cordes
2

Jeśli mówisz o konkretnej aplikacji innej firmy, użyj zmiennej środowiskowej. Większość programów przejdzie bez zmian po całym środowisku, gdy rozwidlają + wykonują nowe procesy.

Więc uruchom tę aplikację z niestandardową zmienną env, którą możesz sprawdzić . np. utwórz dla niego alias alias vs=RUNNING_FROM_VSCODE=1 VSCodelub utwórz skrypt otoki w następujący sposób:

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

Wtedy .bashrcmożesz zrobić

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

Instrukcja arytmetyczna bash (( ))jest prawdziwa, jeśli wyrażenie ma wartość niezerową liczbę całkowitą (dlatego użyłem 1powyżej). Pusty ciąg znaków (dla nie ustawionej zmiennej env var) ma wartość false. Przydaje się to w przypadku zmiennych logicznych bash, ale równie łatwo można użyć truei sprawdzić za pomocą tradycyjnego POSIX

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

Jeśli twoja aplikacja w większości usuwa środowisko dla swoich dzieci , ale nadal przechodzi $PATHbez zmian, możesz użyć tego w swoim opakowaniu:

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

i sprawdź go za pomocą dopasowania do wzorca, takiego jak bash, [[ "${PATH%RUNNING_FROM_VSCODE}" != "$PATH" ]]aby sprawdzić, czy usunięcie sufiksu z PATH to zmieni.

Powinno to nieszkodliwie wykonać jedno dodatkowe wyszukiwanie katalogu, gdy program szuka nie znalezionych poleceń zewnętrznych. /dev/nullzdecydowanie nie jest katalogiem w żadnym systemie, więc można bezpiecznie używać go jako fałszywego katalogu, który szybko spowoduje, ENOTDIRże wyszukiwania PATH nie znajdą tego, czego szukają we wcześniejszych wpisach PATH.

Peter Cordes
źródło
Skrypty otoki są zwykle rozsądnym podejściem, stąd +1. Jedyną niewielką wadą jest to, że jeśli masz 3 programy, możesz chcieć mieć 3 skrypty opakowujące lub jeden skrypt opakowujący, przyjmujący 3 różne argumenty, co może być uciążliwe. Niemniej jednak jest to solidne podejście.
Sergiy Kolodyazhnyy
1

Oto moje 2 centy. Po prostu dodaj go do swojego .bashrc. Zamień na terminalsswoje ulubione terminale i steruj swoimi export.

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
źródło
Nie działałoby to z modelem serwer-klient gnome-terminal.
egmont