Как определить, когда bash-скрипт запускается при связывании клавиш - PullRequest
0 голосов
/ 05 марта 2019

Фон

У меня есть скрипт Bash, который требует ввода данных пользователем.Его можно запустить, вызвав его в терминале или , нажав сочетание клавиш, зарегистрированное в файле конфигурации i3 (или Sway), следующим образом:

bindsym --release $mod+Shift+t exec /usr/local/bin/myscript

Проблема

Я знаю, что могу использовать read -p для запроса в терминале, но это, очевидно, не сработает, когда скрипт запускается через привязку клавиш.В этом случае я могу использовать что-то вроде Yad для создания графического интерфейса, но я не могу определить, когда это не «в терминале».По сути, я хочу иметь возможность сделать что-то вроде этого:

if [ $isInTerminal ]; then
    read -rp "Enter your username: " username
else
    username=$(yad --entry --text "Enter your username:")
fi

Как я могу (автоматически) проверить, был ли мой скрипт вызван из привязки клавиш или запущен в терминале? В идеале это должно быть без пользовательских аргументов командной строки.Другие могут использовать сценарий, и поэтому я хотел бы избежать любой возможности ошибки пользователя через «забытые флаги».


Попытка «Решение»

ЭтоВопрос предлагает проверить, собирается ли stdout на терминал, поэтому я создал этот тестовый скрипт:

#!/usr/bin/env bash

rm -f /tmp/detect.log

logpass() {
    echo "$1 IS opened on a terminal" >> /tmp/detect.log
}
logfail() {
    echo "$1 IS NOT opened on a terminal" >> /tmp/detect.log
}

if [ -t 0 ]; then logpass stdin; else logfail stdin; fi
if [ -t 1 ]; then logpass stdout; else logfail stdout; fi
if [ -t 2 ]; then logpass stderr; else logfail stderr; fi

Однако это не решает мою проблему.Независимо от того, запускаю ли я ./detect.sh в терминале или запускаю его через привязку клавиш, вывод всегда один и тот же:

$ cat /tmp/detect.log
stdin IS opened on a terminal
stdout IS opened on a terminal
stderr IS opened on a terminal

Ответы [ 2 ]

0 голосов
/ 15 марта 2019

Ложный Позитив

Как подсказывает большинство результатов в Google, вы можете использовать tty, что обычно возвращает "не tty" , когда он не запущенв терминале.Однако, похоже, это отличается от сценариев, вызываемых через bindsym exec в i3 / Sway:

/dev/tty1  # From a keybind
/dev/pts/6 # In a terminal
/dev/tty2  # In a console

Хотя tty | grep pts будет частично отвечать на вопрос, он не может различить запуск в консолиvs от привязки клавиш, которая вам не нужна, если вы пытаетесь показать графический интерфейскак родительский процесс.Имея это в виду, что-то подобное может работать:

{
    [ "$PPID" = "1" ] && echo "keybind" || echo "terminal"
} > /tmp/detect.log

Вероятно, безопасное предположение, что процесс systemd всегда будет иметь 1 в качестве PID, но естьнет никакой гарантии, что в каждой системе, использующей i3, также будет использоваться systemd, поэтому, вероятно, этого лучше избегать.


Лучшее решение

Более надежный способ - использовать ps.Согласно PROCESS STATE CODES на странице man:

Для форматов BSD и при использовании ключевого слова stat могут отображаться дополнительные символы:

<    high-priority (not nice to other users)
N    low-priority (nice to other users)
L    has pages locked into memory (for real-time and custom IO)
s    is a session leader
l    is multi-threaded (using CLONE_THREAD, like NPTL pthreads do)
+    is in the foreground process group

Ключздесь + на последней строке.Чтобы проверить это в терминале, вы можете позвонить по номеру ps -Sp <PID>, который будет иметь значение STAT, равное Ss при работе в интерактивном режиме, или S+, если он запускается с помощью связывания клавиш.В столбце STATE вы можете дополнительно очистить его с помощью -o stat=, который также удалит заголовки, а затем направить через grep, чтобы получить следующее:

is_interactive() {
    ps -o stat= -p $$ | grep -q '+'
}

if is_interactive; then
    read -rp "Enter your username: " username
else
    username=$(yad --entry --text "Enter your username:")
fi

Это будет работать не только в терминалеэмулятор и через связывание клавиш i3 / Sway, но даже в необработанном окне консоли, что делает его гораздо более надежным вариантом, чем tty выше.

0 голосов
/ 05 марта 2019

Кажется, что самый простой способ решить вашу реальную проблему - это изменить привязку i3 на

bindsym --release $mod+Shift+t exec /usr/local/bin/myscript fromI3

и сделать

if [[ -n "$1" ]]; then
    echo "this was from a keybind"
else
    echo "this wasn't from a keybind"
fi

в вашем скрипте.

...