Может ли интерактивная оболочка стать неинтерактивной или наоборот?

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.

Из упоминания опции -i и использования слова «операнды» это относится к вызову оболочки , а не к атрибутам, которые можно было бы проверить в работающей оболочке.

Страница руководства 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 есть ссылки на оболочку, которая ведет себя определенным образом «если это не интерактивная оболочка» или «только в интерактивных оболочках или если установлена ​​опция _____». (Есть множество примеров, и это не главное в этом вопросе.)

Поэтому я признаю, что «интерактивный» - это просто удобная метка для набора стандартных «интерактивных» поведений (параметров настроек), описанных на остальной части справочной страницы. Это не фундаментальный термин или объект сам по себе; он не имеет никакого официального определения вне исходного кода оболочки. (В отличие, например, от терминов «дескриптор открытого файла» или «остановленный процесс», которые относятся к абстракциям, встроенным в структуру самого ядра.)

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


Некоторые из последствий того, что оболочка является «интерактивной», актуальны в любом случае только во время вызова , например, какие файлы получены из оболочки до того, как она прочитает другие команды. Тем не менее, есть последствия ( по крайней мере , в Bash) , которые имеют отношение в любое время. Таким образом, для любой запущенной оболочки должен быть способ определить, является ли она интерактивной или нет.

Запуск set +iв интерактивной оболочке Bash приводит к удалению «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}с использованием неустановленного параметра дает аналогичные результаты, еще раз подтверждая, что $-это не «источник правды» для интерактивности оболочки.


Итак, наконец, где хранится характерная черта «интерактивности» оболочки?

И может ли интерактивная оболочка стать неинтерактивной или наоборот? (... изменив эту черту?)

Wildcard
источник

Ответы:

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в старых версиях bash, было ошибкой.
Стефан
1
@Wildcard, если вы посмотрите на исходный код bash, вы, вероятно, обнаружите, что есть interactiveглобальная логическая переменная, которая отображается на iфлаг $-. Изменение этого логического значения не приведет к автоматическому изменению поведения всех интерактивных оболочек. Изменение с интерактивного на неинтерактивное не поддерживается.
Стефан
4
@Wildcard Dash принимает set +iи останавливает отображение приглашения. Это то, что пользователь не должен делать, так что неудивительно, что поведение зависит от оболочки и часто является случайным, а не результатом преднамеренного решения разработчика оболочки.
Жиль "ТАК - перестань быть злым"