Может ли интерактивная оболочка стать неинтерактивной или наоборот?
Примечание. Я провел много исследований по основному вопросу: «В чем разница между интерактивным и неинтерактивным?», И результаты моего исследования заставили меня задать этот вопрос.
Этот вопрос имеет длинную преамбулу отчасти потому, что важно, какой тип определения мы используем для «интерактивного», чтобы ответить на него. Определение может быть произвольной меткой для определенного набора; это может быть описание различных свойств; или он может дать вам информацию, которую вы можете использовать для прогнозирования поведения и понимания цели. Этот последний тип мы можем назвать «определением действия» или «динамическим определением», и он наиболее полезен.
В man 1p sh
приведено следующее определение интерактивной оболочки:
If the -i option is present, or if there are no operands and the shell’s 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}
с использованием неустановленного параметра дает аналогичные результаты, еще раз подтверждая, что $-
это не «источник правды» для интерактивности оболочки.
Итак, наконец, где хранится характерная черта «интерактивности» оболочки?
И может ли интерактивная оболочка стать неинтерактивной или наоборот? (... изменив эту черту?)
источник
Ответы:
Вопрос, который я задам, будет: зачем кому-то это делать?
Вы можете отключить некоторые аспекты интерактивных оболочек, такие как:
PS1= PS2=
отключить подсказкиset +m
отключить контроль работыzle
и все модули завершения вzsh
.Но если вы хотите, чтобы оболочка перестала быть интерактивной, вы можете вместо этого сделать:
Чтобы сказать ему, что нужно получить остальные команды
/some/file
(замените на,/dev/tty
если вы все еще хотите, чтобы команды читались с tty-устройства), хотя все равно будут некоторые отличия от неинтерактивных оболочек, например, для поведенияreturn
или факта. что он все еще будет контролировать работу или:Заменить текущую интерактивную оболочку на неинтерактивную, которая по-прежнему считывает команды с устройства tty.
Обратите внимание, что в bash 4.4
set +i
возвращается сbash: set: +i: invalid option
аналогичным значением в большинстве других оболочек.источник
exec < <(sleep infinity)
используете интерактивную оболочку, у вас есть интерактивная оболочка, которая не очень интерактивна. Оболочка будет по-прежнему считать себя интерактивной, в ней$-
все равно будет содержатьсяi
, но вы не можете. Я не уверен, что есть еще много, чтобы обсудить это.interactive
, так и осталось. То, что вы могли сделатьset +i
в старых версиях bash, было ошибкой.bash
, вы, вероятно, обнаружите, что естьinteractive
глобальная логическая переменная, которая отображается наi
флаг$-
. Изменение этого логического значения не приведет к автоматическому изменению поведения всех интерактивных оболочек. Изменение с интерактивного на неинтерактивное не поддерживается.set +i
и останавливает отображение приглашения. Это то, что пользователь не должен делать, так что неудивительно, что поведение зависит от оболочки и часто является случайным, а не результатом преднамеренного решения разработчика оболочки.