Як перевірити, чи оболонка є вхідною / інтерактивною / пакетною


143

Я думаю, що я розумію відмінності між інтерактивом, входом та пакетною оболонкою. Щоб отримати додаткову допомогу, перегляньте наступні посилання:

Моє запитання полягає в тому, як я можу перевірити команду / умову, якщо я перебуваю на інтерактивній, вхідній або пакетній оболонці?

Я шукаю команду або умову (яка повертається trueабо false) і що я також можу розмістити в операторі if. Наприклад:

if [[ condition ]]
   echo "This is a login shell"
fi

3
Є ще одне питання: чи STDIN та / або STDOUT підключені до tty (терміналу) або трубі (файлу чи процесу)? Це пов'язаний, але виразний тест, як описано в деяких коментарях нижче.
Марк Хадсон

Відповіді:


160

Я припускаю bashоболонку чи подібне, оскільки в тегах немає оболонки.

Щоб перевірити, чи перебуваєте ви в інтерактивній оболонці:

[[ $- == *i* ]] && echo 'Interactive' || echo 'Not interactive'

Щоб перевірити, чи є ви в оболонці для входу:

shopt -q login_shell && echo 'Login shell' || echo 'Not login shell'

Під "партією" я припускаю, що ви маєте на увазі "не інтерактивний", тому перевірки на інтерактивну оболонку має бути достатньо.


12
Для zshкористувачів перевірку оболонки для входу можна зробити за допомогою:if [[ -o login ]] ...
chb

1
Якщо ви хочете знати, чи "користувач" запускав вашу програму проти "cron". [[TERM == "німий"]] && echo "Біг у
кроні"

10
@ErikAronesty Не всі тупі термінали - це сеанси керування.
Кріс Даун

2
"Я припускаю bash shell або подібне, оскільки в тегах немає оболонки". - Логіка цього твердження справді прекрасна! :)
Майкл Ле Барб'є Грюневальд

2
@antonio Це тому, що ваше цитування неправильне, $-розширюється в поточній оболонці. Якщо ви будете використовувати одиничні лапки навколо повного виразу, ви отримаєте правильний результат:bash -c '[[ $- == *i* ]] && echo "Interactive" || echo "Not interactive"'
Chris Down

33

У будь-якій оболонці в стилі Борна iопція вказує, чи оболонка інтерактивна:

case $- in
  *i*) echo "This shell is interactive";;
  *) echo "This is a script";;
esac

Немає портативного і повністю надійного способу перевірити наявність оболонки для входу. Ksh і zsh додати lдо $-. Bash встановлює login_shellпараметр, з яким ви можете запитувати shopt -q login_shell. Портативно перевіряйте, чи $0починається з -: оболонки зазвичай знають, що вони оболонки для входу, тому що абонент додав -префікс до нуля аргументу (зазвичай це ім'я або шлях виконуваного файлу). Це не вдається виявити специфічні для оболонки способи виклику оболонки для входу (наприклад ash -l).


(...) тому, що абонент - я думаю, у цьому фрагменті чогось не вистачає.
Пьотр Доброгост

Ідеально було б, якби $0завжди починалося з -того, як воно було розпочато. Але є хоча б один виняток: це не завжди вірно з bash, навіть якщо він повинен бути оболонкою для входу. Спробуйте це у своєму полі: викликайте bash --login, а потім $0все одно читає bash.
Wirawan Purwanto

@WirawanPurwanto Я не впевнений, що я розумію ваш коментар. Це не те, що я написав у своєму останньому реченні?
Жиль

@Gilles: Ви маєте рацію. Вибачте, що я пропустив ваше останнє речення.
Wirawan Purwanto

24

рибний панцир

Ось відповідь на fishвипадок, якщо інші користувачі натрапляють на цю сторінку.

if status --is-interactive
    # ...
end

if status --is-login
    # ...
end

echo "darn, I really wanted to have to use globs or at least a case statement"

Документація на рибу: ініціалізація


1
-1 за зайву редакцію.
Нік Бастін

6
Якщо хтось цікавиться коментарем @ NickBastin, він мав справедливу точку, тому я зробив редагування. Первісна кількість снодійності тепер скоротилася навпіл.
ohspite

18

csh / tcsh

Для cshі tcshя наступний в моєму .cshrcфайлі:

if($?prompt) then               # Only interactive shells set $prompt
    ...
endif

Спеціально для tcshзмінної loginshвстановлено оболонку входу:

if($?loginsh) then              # A login shell..
    ...
endif

( tcshтакож має змінну, shlvlяка встановлюється на кількість вкладених оболонок, де оболонка входу має значення 1.)


2
PS1не працює для тестування на інтерактивну оболонку. Він майже завжди встановлений в інтерактиві, але ви можете його зняти. Це дуже нерідко встановлює в неінтерактивної оболонці, так як багато систем корабля з export PSв /etc/profile.
Жиль

@Gilles Дякую за виправлення та редагування
Ендрю Штейн

17

Інший спосіб - перевірити результат tty

if [ "`tty`" != "not a tty" ]; then

10
... або використовувати [ -t 0 ]для перевірки, чи STDIN - це tty. Ви також можете використовувати 1 (STDOUT) або 2 (STDERR) залежно від ваших потреб.
дероберт

@derobert - дякую, що показали мені щось нове
Адріан Корніш

10
Це різне випробування. Можна мати неінтерактивну оболонку, вхід якої є терміналом (у будь-який момент, коли ви запускаєте скрипт у терміналі!), І можливо (хоч і рідко) мати інтерактивну оболонку, яка приймає вхід не з терміналу.
Жиль

@Gilles, якщо оболонка була інтерактивною та закритою, залишаючи дитину disownта живу, ttyпрацювала найкраще, щоб знати, що вона більше не є інтерактивною, поки $-не змінилася; Мені все одно спантеличено, що є найкращим підходом.
Сила Водолія

5
@AquariusPower Тоді, що ви хочете перевірити, це не інтерактивна оболонка, а те, чи є стандартним входом термінал. Використовуйте [ -t 0 ]. PS У своєму попередньому коментарі я писав, що "існує сильна кореляція" - я забув "крім надзвичайно поширеного випадку сценарію, розпочатого з #!/bin/shподібного", який не є інтерактивним, але може бути підключений до терміналу.
Жиль

8

UNIX / Linux має команду перевірити, чи перебуваєте ви на терміналі.

if tty -s
then
echo Terminal
else
echo Not on a terminal
fi

1
Це працює і в dash.
Кен Шарп

7

Ви можете перевірити, чи stdin є терміналом:

if [ -t 0 ]
then
    echo "Hit enter"
    read ans
fi

3

Щоб перевірити, чи працює сценарій в інтерактивній або неінтерактивній оболонці, я перевіряю у своїх сценаріях наявність підказки, що зберігається у $PS1змінній:

if [ -z $PS1 ] # no prompt?
### if [ -v PS1 ]   # On Bash 4.2+ ...
then
  # non-interactive
  ...
else
  # interactive
  ...
fi

Про це я дізнався тут: https://www.tldp.org/LDP/abs/html/intandnonint.html


1

iне є правильним варіантом пошуку. -i- змусити інакше неінтерактивну оболонку стати інтерактивною. Правильна опція, включена автоматично -s, але Bash, на жаль, не справляється з цим правильно.

Вам потрібно перевірити, чи $-містить він s(це надано для автоматичного активації) чи він містить i(це не надається для автоматичного активації, але офіційно пов'язане лише з параметром -iкомандного рядка оболонки).


1
sБуло б, якщо оболонка читає команди зі stdin, а не інтерактивна. Інтерактивна оболонка не обов'язково читає команди зі stdin (спробуйте zsh -i < /dev/null, хоча zsh, здається, тут є винятком). І оболонка може читати команди з stdin і не бути інтерактивною (як-от sh < fileабо echo 'echo "$1"' | sh -s foo bar).
Стефан Шазелас

2
Що я хотів зазначити, це те, що в оригінальній програмі «Борн Шелл» немає «я» в $ - навіть тоді, коли вона призначена бути інтерактивною.
schily

Гаразд, але на U&L, "оболонка", як правило, відноситься до сучасних оболонок. Оболонка Борна, як правило, вважається реліктом, і ваш власний варіант недостатньо основний, щоб очікувати, що люди дізнаються про що ви говорите, якщо ви не зробите це явним. Згадане питання, [[...]]що передбачає ksh / bash / zsh. У вас є пункт як історія записка , що перевірка iін $-не працюватиме в оболонці Bourne. Але потім перевірка на те s, що не буде надійно, працюватиме і там. Ви також хочете перевірити наявність [ -t 0 ]та i; навіть тоді це було б обдурене у таких кутових випадках, якecho 'exec < /dev/tty; that-check' | sh'
Стефан Шазелас

Solaris до Solaris 10 поставляється з оригінальною шкаралупою Bourne, і навіть підвіконня включає фартух. 10 помилок, які, як відомо, знаходяться в оболонці з часу SVr4. Тож додавання натяку на «Борн Шелл» не є капелюшком сумлінним, як ви можете повірити. zsh з іншого боку недостатньо сумісний, він, наприклад, не спрацьовує, коли ви намагаєтеся запустити "конфігурувати" з zsh, тому остерігайтеся налаштувати / bin / sh, щоб вказати на zsh. BTW: мій Bourne Shell встановлює -i за замовчуванням, якщо він вирішить бути інтерактивним.
schily

3
Я помічаю, що POSIX, здається, не вимагає $ - містить i (який, здається, вимагає s), я підніму питання про ML Austin group.
Стефан Шазелас
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.