Как скрипт Bash может рассказать, как он был запущен?

10

У меня есть сценарий Bash, который я пытался сделать, чтобы помочь мне выполнить довольно сложную команду с небольшими изменениями, о которых она спрашивала бы меня через echo и read.

Я нашел решения, чтобы заставить его запустить терминал для выполнения команды, но меня это не интересует. Я хотел бы, чтобы, если я выделюсь и просто нажму Enter на нем в Nautilus (он запускается с помощью Run Software), он просто аккуратно выведет уведомление «Пожалуйста, запустите это из терминала».

Я могу заставить всплывающее окно появиться - как я знаю команду - но я не могу заставить скрипт Bash сказать, запущен ли он внутри терминала или нет, кажется, он всегда так думает. Это вообще возможно?

Aescula
источник

Ответы:

10

Из- man bashпод УСЛОВНЫХ ВЫРАЖЕНИЙ :

-t fd  
    True if file descriptor fd is open and refers to a terminal.

Предполагая, что fd 1 является стандартным, if [ -t 1 ]; thenдолжен работать для вас. Руководство по написанию сценариев Advanced Shell утверждает, что -tэтот способ не будет выполнен ssh, и поэтому тест (с использованием stdin, а не stdout) должен быть:

if [[ -t 0 || -p /dev/stdin ]]

-pпроверяет, существует ли файл и является ли он именованным каналом Тем не менее , на опыте я бы заметил, что это не так для меня: происходит -p /dev/stdinсбой как для обычных терминалов, так и для сеансов ssh, тогда как if [ -t 0 ](или -t 1) работает в обоих случаях (см. Также комментарии Жиля ниже о проблемах в этом разделе Руководства по расширенным сценариям оболочки ).


Если основной проблемой является специализированный контекст, из которого вы хотите вызвать скрипт, чтобы он вел себя так, как нужно для этого контекста, вы можете обойти все эти технические моменты и немного сэкономить, используя оболочку и пользовательскую переменную:

!#/bin/bash

export SPECIAL_CONTEXT=1
/path/to/real/script.sh

Назовите это live_script.shили что-то еще и дважды щелкните по нему. Конечно, вы могли бы сделать то же самое с аргументами командной строки, но оболочка все еще была бы необходима, чтобы сделать точку и щелкнуть в браузере файлов GUI.

лютик золотистый
источник
5
это правильный ответ - так же POSIX говорит, что оболочка должна определять, интерактивен он или нет.
mikeserv
2
@DanielAmaya - если вы перенаправляете ввод, скрипт не запускается на терминале. Вопрос в том, как определить, запускается ли скрипт на терминале.
mikeserv
2
Вы уверены в использовании ||внутри, [ … ]как это? Если вы используете [[ … ]]то, это было бы хорошо, но обычно ||используется для разделения команд, и [ -t 0это неправильный вызов, [потому что его последний ]отсутствует. Там обычно нет команды -pлибо. Я согласен с тестированием терминала; это, вероятно, способ сделать это. Это просто синтаксис, который меня беспокоит.
Джонатан Леффлер
1
@JonathanLeffler Верно; это должно привести к синтаксической ошибке, так как оператор оболочки ||рассматривается перед необходимым последним ]аргументом для [.
chepner
3
Этот раздел из Руководства по расширенному написанию сценариев содержит несколько ошибок. PS1не является надежным тестом, чтобы определить, является ли оболочка интерактивной. «Если сценарий должен проверять, выполняется ли он в интерактивной оболочке», это также сбивает с толку: должно быть, если некоторый код нуждается в проверке - сценарий обычно не выполняется в интерактивной оболочке (но это может быть, если он получен) , Тестирование iin $-- это правильный способ проверить, является ли оболочка интерактивной. Тестирование -t 0или -t 2правильный способ определить, работает ли сценарий в терминале, который отличается от интерактивного.
Жиль "ТАК - перестань быть злым"
0

Используйте переменную bash $ SHLVL, чтобы определить уровень вложенности оболочки. В скрипте, запущенном «raw», при двойном щелчке он будет равен 1, в скрипте, запущенном в терминале, он будет равен 2.

#!/bin/bash
if (( SHLVL < 2 )) ; then
    echo "Please run this from a terminal."
    read -p "Press <Enter> to close this window"
    exit 1
fi
# rest of script
Эд Рэндалл
источник
0

Хотя ответ Златовласка, вероятно, является правильным в типичном случае, кажется, что есть крайние случаи. В моем собственном случае мой xserver настроен на запуск с tty1и он никогда не покидает tty. Если Xorg stdout- это TTY, то, по-видимому, клиенты будут иметь этот TTY, связанный с дескриптором файла по умолчанию.

Вот как я решил свою проблему:

#!/bin/bash
isxclient=$( readlink /dev/fd/2 | grep -q 'tty' && [[ -n $DISPLAY ]] ; echo $? )
if [[ ! -t 2  || $isxclient == "0" ]]; then
        notify-send "Script wasn't started from an interactive shell"
else
        echo "Script was started from an interactive shell"
fi

Я не проверял это, чтобы увидеть, работает ли он на более стандартной конфигурации X, и я также очень сомневаюсь, что это единственный крайний случай. Если кто-то найдет более приемлемое решение, пожалуйста, вернитесь и сообщите нам.

JMW
источник
-2

Другой, используя опции Баш набор внутренних переменных, $-.

От .bashrc,

# If not running interactively, don't do anything
case $- in
    *i*) ;;
    *) return;;
esac
XAE
источник
интерактивная оболочка не обязательно связана с терминалом. в то время как один начали с этим соединением , автоматически запускаются интерактивной, это также возможно: cmd | sh -i | cmd.
mikeserv
Этот код выполняется в скрипте. Он не будет интерактивным, даже если он работает в терминале.
Жиль "ТАК - перестань быть злым"