Bash: Як визначити, чи відкривається термінал стороннім додатком


9

Я хочу, щоб мій скрипт bash (конкретно мій ~/.bashrc) робив щось, тільки якщо термінал був відкритий мною безпосередньо, і робити щось інше, якщо він був відкритий через додаток, наприклад VS Code. Як я можу визначити, що таке справа? Чи є для цього змінною? Заздалегідь спасибі.


1
Там є спосіб, першою моєю відповіддю було б перейти з другим прикладом в askubuntu.com/a/1042727/295286 . Спробуйте відкрити VS і запустити envкоманду. Подивіться, чи існує змінна для VS змінна.
Сергій Колодяжний

1
Якщо нічого немає, спробуйте це навпаки: подивіться, чи емулятор терміналу встановлює змінну. Я використовую yakuakeмінливий PULSE_PROP_OVERRIDE_application.name=Yakuakeнабір і xtermнабори XTERM_VERSION=XTerm(322)на своїй машині.
десерт

@SergiyKolodyazhnyy Ви б написали відповідь про підхід із змінним середовищем, будь ласка?
десерт

@dessert Я б хотів, але у мене не встановлено VS, ні ОП не відповів, якщо є якась певна змінна середовище, на яку ми можемо зав'язатись.
Сергій Колодяжний

@SergiyKolodyazhnyy Я також не маю, але в назві питання говориться стороннє додаток, і я вважаю, що він працює як будь-який термінальний емулятор - я думаю, що відповідь, як env >env_term1в одному емуляторі, env >env_term2в другому - і як використовувати те, що diff env_term{1,2}говорить, дуже корисно. В кінці кінців, OP каже , наприклад , VS Code .
десерт

Відповіді:


10

Ви, ймовірно, могли це зробити, повернувшись назад до корінних оболонок і працюючи над тим, чи це було розпочато чимось, що прирівнюється до "ви", чи іншою програмою.

Отримайте PID оболонки (ідентифікатор процесу), а з цього його PPID (ідентифікатор батьківського процесу). Продовжуйте підніматися до тих пір, поки не дістанетесь до чогось, що говорить вам, звідки воно прийшло. Можливо, вам доведеться експериментувати на своїй системі - принаймні, я не знаю, чи буде вона універсальною.

Наприклад, в моїй системі дістаньте PID оболонки та використовуйте, psщоб показати, що це bash:

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

Отримайте PPID 18852:

$ ps -o ppid= -p 18852
18842

Дізнайтеся, що таке PPID (18842):

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

Ми можемо бачити, що це gnome-terminal, тобто емулятор термінала / вікно терміналу. Можливо, це досить добре для вас, якщо ваша оболонка, запущена іншою програмою, не працює у вікні емулятора терміналу.

Якщо це недостатньо добре, перейдіть на інший рівень:

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

Це говорить нам, що gnome-terminalбуло розпочато init. Я підозрюю, що ваша оболонка, запущена іншою програмою, матиме щось інше.


... або, можливо, піднявши результатpstree -s $$
steeldriver

9
"Це говорить нам про те, що gnome-термінал був запущений init" Я вважаю малоймовірним, що init запустить термінальні вікна. Швидше, все, що почалося, gnome-термінал помер, і gnome-термінал був перероджений для init. Перевіряючи гном-термінал, схоже, це подвійні вилки. Тож коли він виконується, він спочатку розщеплюється та вбиває початковий процес, продовжуючи новий.
JoL

@JoL Справедливий пункт. Цей initпроцес не є під 1, але не впевнений, що це щось змінить.
kasperd

Дуже дякую! Мені вдалося виявити, що ні Код VS, ні Eclipse не запускають термінал як дитина gnome-terminal. Я виконав свою команду під if [ $(pstree -s $$ | grep "gnome-terminal" -c) -gt 0 ]; then ...і це спрацювало.
PaperBag

9

Що стосується коду Visual Studio, очевидно, існує спосіб встановити додаткові змінні середовища для інтегрованого терміналу . Отже, налаштуйте Visual Studio для використання цього конфігурації:

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

І всередині ~/.bashrc:

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

Загалом, ви можете покластися на середовище, яке надається bashпроцесу. Наприклад, в $TERMзмінної , і запустити аналогічну if..then...else...fiгілку для [ "$TERM" = "xterm" ]или что - то ще. У кожному конкретному випадку ви можете досліджувати відмінності оточуючого середовища за допомогою запуску envв кожній консолі, зберігаючи їх у файлі як у env > output_console1.txt, так і diff output_console1.txt output_console2.txtяк пропонується десертом у коментарях .


$Env:varне є синтаксисом змінних середовища в Bash. Для мене це схоже на Powershell.
Дітріх Епп

@DietrichEpp Так, я спочатку досліджував способи встановлення додаткових змінних середовищ у Visual Studio, але помітив, що для відповідей використовувався PowerShell. Тож $fooдостатньо. Кави, мабуть, недостатньо.
Сергій Колодяжний

Для загального випадку сторонніх програм, у яких немає налаштування env, ви можете встановити власну env var у обгортці перед запуском програми. Дивіться мою відповідь .
Пітер Кордес

2

Якщо ви говорите про один конкретний сторонній додаток, тоді використовуйте змінну середовища. Більшість програм пройдуть уздовж всього середовища без змін, коли вони розщеплюють + виконують нові процеси.

Отже, запустіть цю програму зі спеціального env var, на який ви можете перевірити . наприклад, зробіть псевдонім для нього подібним alias vs=RUNNING_FROM_VSCODE=1 VSCodeабо зробіть такий сценарій обгортки:

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

Тоді у вашому .bashrc, ви можете зробити

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

Арифметичне твердження bash (( ))є істинним, якщо вираз оцінюється на ненульове ціле число (саме тому я використовував 1вище). Порожній рядок (для невстановленої env var) помилковий. Це приємно для bash булевих змінних, але ви можете так само легко використовувати trueі перевірити це за допомогою традиційного POSIX

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

Якщо ваш додаток очищає навколишнє середовище для своїх дітей , але все ще залишається $PATHнезмінним, ви можете використовувати це у своїй обгортці:

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

і перевірте це на відповідність шаблону типу bash, [[ "${PATH%RUNNING_FROM_VSCODE}" != "$PATH" ]]щоб перевірити, чи змінює суфікс із PATH його.

Це повинно нешкідливо зробити один додатковий пошук каталогу, коли програма шукає не знайдені зовнішні команди. /dev/nullце, безумовно, не каталог у будь-якій системі, тому його безпечно використовувати як фальшивий каталог, який швидко призведе до того, що ENOTDIRPATH-пошуки не знайдуть те, що шукають у попередніх записах PATH.


Сценарії для обгортання зазвичай є розумним підходом, отже, +1. Єдиним незначним недоліком є ​​те, що якщо у вас є три програми, ви можете мати 3 сценарії обгортки або один скрипт обгортки з 3-ма різними аргументами, що може зробити це нудним. Тим не менш, це твердий підхід.
Сергій Колодяжний

1

Ось мої 2 копійки. Просто додайте його до свого .bashrc. Замініть terminalsулюблені термінали і 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

Це не працює з моделлю сервера-клієнта терміналу gnome-терміналу.
Егмонт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.