Чи може інтерактивна оболонка стати неінтерактивною чи навпаки?


16

Чи може інтерактивна оболонка стати неінтерактивною чи навпаки?

Примітка. Я провів багато досліджень з основного питання "Яка різниця між інтерактивним та неінтерактивним?", І результати мого дослідження змусили мене задати це питання.

Це питання частково має довгу преамбулу, оскільки важливо, який тип визначення ми використовуємо для "інтерактивного", щоб відповісти на нього. Визначення може бути довільною міткою для певного набору; це може бути описовим для різних властивостей; або він може дати вам інформацію, яку ви можете використовувати для прогнозування поведінки та розуміння мети. Останній тип ми можемо назвати "визначенням дії" або "динамічним визначенням", і він є найбільш корисним.


В man 1p shдається таке визначення інтерактивної оболонки:

   If the -i option is present, or  if  there  are  no  operands  and  the
   shells  standard  input and standard error are attached to a terminal,
   the shell is considered to be interactive.

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

Сторінка чоловіка Bash дещо по-іншому формулює це:

   An interactive shell is one started without  non-option  arguments  and
   without the -c option whose standard input and error are both connected
   to terminals (as determined by isatty(3)), or one started with  the  -i
   option.   PS1 is set and $- includes i if bash is interactive, allowing
   a shell script or a startup file to test this state.

Визначення в першому реченні знову лише стосується початку оболонки.

Друге речення (на мій прочитання) визначає умови, які використовуються як проксі, щоб встановити, чи була запущена оболонка певними способами, які визначаються як зробити її "інтерактивною".

Зауважте, що я не трактую це речення як: "Оболонка bash є інтерактивною тоді і лише тоді, коли $-містить" i "." $-здається, це просто зручний показник, а не визначення інтерактивного. Це вкрай важливо для мого питання.


Обидва ці ( shвизначення POSIX та визначення Bash) - це механічні визначення, які вказують, за яких обставин мітка "інтерактивна" застосовується до запущеної оболонки. Вони не є визначеннями дій, оскільки вони не дають жодних наслідків для цієї мітки.

Однак я бачу, що на всій решті сторінки Bash man посипаються посилання на оболонку, яка поводиться певними способами, "якщо це не інтерактивна оболонка" або "тільки в інтерактивних оболонках, або якщо встановлено _____ параметр". (Є численні приклади, і це не головний пункт цього питання.)

Тож я прийму, що "інтерактивний" - це лише зручна мітка для колекції типових "інтерактивних" поведінок (налаштування опцій), описаних на всій іншій сторінці сторінки. Це сам по собі не фундаментальний термін чи об'єкт; воно не має авторитетного визначення поза вихідним кодом оболонки. (На відміну, наприклад, терміни "дескриптор відкритого файлу" або "зупинений процес", які посилаються на абстракції, вбудовані в дизайн самого ядра.)

(Хоча це також визначено у визначенні POSIX sh, ця сторінка [ man 1p sh] має набагато менше використання ", якщо оболонка не є інтерактивною" та подібними висловлюваннями, ніж man bashмає, і майже виключно фокусується на різницях у часі виклику, тому я зупинюсь на Bash з цього моменту і далі.)


Деякі з наслідків оболонки, яка є "інтерактивною", в будь-якому разі є актуальною лише під час виклику , наприклад, які файли отримує оболонка, перш ніж читати інші команди. Однак є наслідки (принаймні у Bash), які є актуальними в будь-який час. Таким чином, повинен бути спосіб сказати для будь-якої запущеної оболонки, чи є вона інтерактивною чи ні.

Запуск set +iв інтерактивній оболонці Bash призводить до видалення "i" зі вмісту $-.

Питання: чи це насправді означає, що оболонка більше не є інтерактивною?

За точним визначенням Баша, це не повинно, оскільки ніде у цьому визначенні не потрібно, щоб "я" був присутній у $-:

   An interactive shell is one started without  non-option  arguments  and
   without the -c option whose standard input and error are both connected
   to terminals (as determined by isatty(3)), or one started with  the  -i
   option.

Чітке читання точного визначення також викликає питання: Якщо stdin або stderr інтерактивного терміналу перенаправляються, щоб вони більше не були підключені до терміналів, чи стає оболонка неінтерактивною?

( Здається, що відповідь на це - «ні», і довідкова сторінка могла включити модифікатор: «чий стандартний вхід і помилка підключені до терміналів ... під час виклику », але я не знаю остаточно.)


Якщо відповідь: "Ні, оболонка не може стати неінтерактивною, ні навпаки", то який остаточний спосіб визначити, чи оболонка інтерактивна?

Інший спосіб: якщо є поведінка "інтерактивної оболонки", яка зберігається і надалі set +i, то що застосовується для визначення того, що ця поведінка повинна продовжувати застосовуватися?


Щоб ніхто сумнів його: Там є поведінка оболонки залученого в інтерактивному режимі, які зберігаються після set +iі поведінки оболонки викликається не інтерактивно , які зберігаються після set -i. Для прикладу розглянемо наступний уривок із man bash:

COMMENTS
   In a non-interactive shell, or an interactive shell in which the inter-
   active_comments  option  to  the  shopt  builtin  is enabled (see SHELL
   BUILTIN COMMANDS below), a word beginning with # causes that  word  and
   all  remaining  characters  on that line to be ignored.  An interactive
   shell without the interactive_comments option enabled  does  not  allow
   comments.  The interactive_comments option is on by default in interac-
   tive shells.

Таким чином, відмінивши interactive_commentsопцію, ми можемо побачити різницю між інтерактивними та неінтерактивними оболонками. Стійкість цієї різниці демонструється наступним сценарієм:

#!/bin/bash

# When the testfile is run interactively,
# all three comments will produce an error
# (even the third where 'i' is not in '$-').
# When run noninteractively, NO comment will
# produce an error, though the second comment
# is run while 'i' IS in '$-'.

cat >testfile <<'EOF'
shopt interactive_comments
shopt -u interactive_comments
shopt interactive_comments
echo $-
#first test comment
set -i
echo $-
#second test comment
set +i
echo $-
#third test comment
EOF

echo 'running bash -i <testfile'
bash -i <testfile
echo 'running bash <testfile'
bash <testfile

Це підтверджує, що "інтерактивні" та "мають iзначення $-" не є рівнозначними.

Аналогічний тест ${parameter:?word}з використанням невстановленого параметра дає подібні результати, знову підтверджуючи, що $-це не "джерело істини" для інтерактивності оболонки.


Отже, нарешті, де зберігається остаточна ознака «інтерактивності» оболонки?

І чи може інтерактивна оболонка стати неінтерактивною чи навпаки? (... змінивши цю ознаку?)


Відповіді:


9

Питання, яке я задаю, було б, чому хто-небудь хоче це робити?

Ви можете відключити деякі аспекти інтерактивних оболонок, наприклад:

  • PS1= PS2= щоб відключити підказки
  • set +m відключити контроль роботи
  • вимкнути історію в деяких оболонках
  • можливо, ви зможете вивантажити zleі всі модулі завершення в zsh.

Але якщо ви хочете, щоб оболонка перестала бути інтерактивною, ви можете замість цього зробити:

. /some/file; exit

Скажіть, щоб отримати решту команд /some/file(замінити, /dev/ttyякщо ви все ще хочете, щоб команди читалися з пристрою tty), хоча все-таки будуть деякі відмінності від неінтерактивних оболонок, наприклад, щодо поведінки returnчи факту що він все ще буде контролювати роботу або:

exec myshell /dev/tty

Щоб замінити поточну інтерактивну оболонку неінтерактивною, яка все ще читає команди з пристрою tty.

Зауважте, що з bash 4.4 set +iповертається з bash: set: +i: invalid optionподібним у більшості інших оболонок.


Абсолютно погодився, що це було б смішно робити. Як я вже згадував, моя концепція "інтерактивної" полягає в тому, що це лише сукупність поведінки за замовчуванням, які корисні при взаємодії зі своєю оболонкою. Якщо ви можете змінити кожну з цих форм поведінки окремо, а ви зміните кожну, то питання "Чи все ж це інтерактивна оболонка?" просто смішна семантика; це навіть не важливе питання. Однак ....
Wildcard

1
@Wildcard, якщо ви працюєте exec < <(sleep infinity)в інтерактивній оболонці, у вас є інтерактивна оболонка, яка не дуже інтерактивна. Оболонка все-таки вважатиме себе інтерактивною, оскільки $-вона все ще міститиме i, але ви не можете. Я не впевнений, що можна набагато більше обговорити про це.
Стефан Шазелас

2
@Wildcard, якщо оболонку було запущено як interactive, вона залишається такою. Те, що ви могли зробити set +iу старих баш-версіях, було помилкою.
Стефан Шазелас

1
@Wildcard. Якщо ви подивитеся на вихідний код bash, ви, ймовірно, знайдете interactiveглобальну булеву змінну, яка відображається на iпрапор $-. Якщо змінити булевий характер, автоматично не зміниться поведінка інтерактивних оболонок. Перехід від інтерактивного до неінтерактивного не підтримується.
Стефан Шазелас

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