Як сценарій Bash може розповісти, як це було запущено?


11

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

Я знайшов рішення, щоб змусити його запустити термінал для виконання команди, але мене це не цікавить. Я хотів би це зробити, якщо я виділяю пробіл і просто натискаю Enter на ньому в Nautilus (змушуючи його запускати запуск програмного забезпечення), він просто обережно спливе повідомлення з повідомленням: "Будь ласка, запустіть це з терміналу".

Я можу дозволити спливаюче вікно, як це знаю, як я знаю команду, - але я не можу отримати сценарій Bash, щоб сказати, запускається він всередині терміналу чи ні, здається, завжди так думаю. Чи можливо це навіть?

Відповіді:


10

З- 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чи що-небудь та двічі клацніть по ньому. Можна, звичайно, виконати те ж саме, що й аргументи командного рядка, але для роботи в браузері файлів GUI все ще знадобиться обгортка.


5
це правильна відповідь - це також те, як POSIX каже, що оболонка повинна визначати, чи є вона інтерактивною чи ні.
mikeserv

2
@DanielAmaya - якщо ви перенаправляєте введення, сценарій не запускається на терміналі. Питання в тому, як визначити, чи виконується сценарій на терміналі.
mikeserv

2
Ви впевнені у використанні ||всередині [ … ]такого? Якщо ви використовуєте, [[ … ]]то це було б добре, але, як правило ||, використовується для розділення команд, і [ -t 0це неправильне виклик, [оскільки його остання ]відсутня. Як правило, це також і команда -p. Я згоден з тестуванням терміналу; це, мабуть, спосіб зробити це. Мене хвилює лише синтаксис.
Джонатан Леффлер

1
@JonathanLeffler Right; що повинно створити синтаксичну помилку, оскільки оператор оболонки ||бачиться перед необхідним остаточним ]аргументом для [.
чепнер

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, і також дуже сумніваюся, що це єдиний крайній випадок. Якщо хтось знайде більш прийнятне рішення, будь ласка, поверніться та скажіть нам.


-2

Інший, використовуючи опції Баш набір внутрішніх змінних, $-.

З .bashrc,

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

інтерактивна оболонка не обов'язково підключена до терміналу. в той час як один почали з цим з'єднанням , автоматично запускаються інтерактивної, це також можливо: cmd | sh -i | cmd.
mikeserv

Цей код виконується в сценарії. Він не буде інтерактивним, навіть якщо він працює в терміналі.
Жил "ТАК - перестань бути злим"
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.