Я пытаюсь написать функцию, чтобы заменить функциональность exit
встроенной, чтобы предотвратить выход из терминала.
Я попытался использовать SHLVL
переменную окружения, но она не меняется внутри подоболочек:
$ echo $SHLVL
1
$ ( echo $SHLVL )
1
$ bash -c 'echo $SHLVL'
2
Моя функция заключается в следующем:
exit () {
if [[ $SHLVL -eq 1 ]]; then
printf '%s\n' "Nice try!" >&2
else
command exit
fi
}
Это не позволит мне использовать exit
внутри подоболочек:
$ exit
Nice try!
$ (exit)
Nice try!
Что такое хороший метод, чтобы определить, нахожусь ли я в подоболочке?
(...)
наследуют все свойства родительского процесса. Предоставленные ответы являются более надежными решениями для определения уровня вашей оболочки.BASH_SUBSHELL
ответ (даже если спорный) не будет применяться к этому вопросу.Ответы:
В Bash вы можете сравнить
$BASHPID
с$$
Если вы не в bash, то
$$
должны оставаться такими же в подоболочке, поэтому вам потребуется другой способ получения вашего фактического идентификатора процесса.Один из способов получить ваш настоящий пид это
sh -c 'echo $PPID'
. Если вы просто поместите это на равнине,( … )
это может не сработать, поскольку ваша оболочка оптимизировала ответвление. Попробуйте дополнительные команды no-op,( : ; sh -c 'echo $PPID'; : )
чтобы заставить его думать, что подоболочка слишком сложна для оптимизации. Заслуга John1024 на переполнение стека для этого подхода.источник
(sh -c 'echo $PPID'; : )
- см. Мой комментарий к ответу John1024 .Как насчет
BASH_SUBSHELL
?источник
[это должен был быть комментарий, но мои комментарии, как правило, удаляются модераторами, так что это останется ответом, который я мог бы использовать в качестве ссылки, даже если удален]
Использование
BASH_SUBSHELL
совершенно ненадежно, поскольку в некоторых подоболочках его можно установить только на 1 , а не во всех.Прежде чем утверждать, что подпроцесс, в котором запускается конвейерная команда, не является действительно реальной подоболочкой, рассмотрите этот
man bash
фрагмент:и практические последствия - важно, является ли фрагмент сценария выполнением подпроцесса или нет, что не важно, а не какая-то терминологическая ошибка.
Единственное решение, как уже объяснялось в ответах на этот вопрос, состоит в том, чтобы проверить, является ли он
$BASHPID
равным$$
или, по-видимому, гораздо менее эффективным:источник
BASH_SUBSHELL
установлен довольно надежно, но получить правильное значение неправильно. Обратите внимание на то, что говорят документы : «Увеличивается на единицу в каждой среде подоболочек или подоболочек, когда оболочка начинает выполняться в этой среде». Я думаю, что в примере с конвейером bash еще не начал выполняться в этой подоболочке, когда раскрывается переменная. Вы можете сравнитьecho $BASH_VERSION
сdeclare -p BASH_VERSION
- последний должен надежно вывести 1 с трубами, фоновыми заданиями и т. Д.eval 'echo $BASH_SUBSHELL $BASHPID' | cat
будет выводить 1 дляBASH_SUBSHELL
, потому что переменная раскрывается после начала выполнения.subshell_level
действительно откладывается в случае конвейеров переднего плана , что, вероятно, имеет какую-то причину, но я не могу разобрать ;-)echo $$ $BASHPID $BASH_SUBSHELL | cat
.