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

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

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

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

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

решение1

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

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

Если предположить, что fd 1 — это стандартный выход, if [ -t 1 ]; thenто вам должно подойти.Расширенное руководство по написанию сценариев оболочкиутверждает, что -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или что-то еще и дважды щелкните это вместо этого. Конечно, вы могли бы сделать то же самое с аргументами командной строки, но оболочка все равно понадобится, чтобы заставить работать point and click в файловом браузере с графическим интерфейсом.

решение2

Используйте переменную 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

Примечание: символ $ не требуется при проверке числовых переменных внутри (( )).

решение3

Хотя ответ goldilocks', вероятно, верен в типичном случае, похоже, что существуют пограничные случаи. В моем случае мой xserver настроен на запуск с tty1и никогда не покидает этот tty. Если Xorg's 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, и я также очень сомневаюсь, что это единственный крайний случай. Если кто-то найдет более общеприменимое решение, пожалуйста, вернитесь и сообщите нам.

решение4

Другой, с помощью параметров bash, устанавливает внутреннюю переменную, $-.

От .bashrc,

# If not running interactively, don't do anything
case $- in
    *i*) ;;
    *) return;;
esac

Связанный контент