Estou tentando escrever uma função para substituir a funcionalidade do exit
built-in para me impedir de sair do terminal.
Eu tentei usar a SHLVL
variável de ambiente, mas ela não parece mudar nos subshells:
$ echo $SHLVL
1
$ ( echo $SHLVL )
1
$ bash -c 'echo $SHLVL'
2
Minha função é a seguinte:
exit () {
if [[ $SHLVL -eq 1 ]]; then
printf '%s\n' "Nice try!" >&2
else
command exit
fi
}
Isso não permitirá que eu use exit
dentro de subshells:
$ exit
Nice try!
$ (exit)
Nice try!
Qual é um bom método para detectar se estou ou não em um subshell?
(...)
herdam todas as propriedades do processo pai. As respostas fornecidas são soluções mais robustas para determinar o nível do seu shell.BASH_SUBSHELL
resposta (mesmo que controversa) não se aplicaria a essa pergunta.Respostas:
No bash, você pode comparar
$BASHPID
com$$
Se você não está no bash,
$$
deve permanecer o mesmo em um subshell, portanto, você precisará de outra maneira de obter seu ID de processo real.Uma maneira de obter seu pid real é
sh -c 'echo $PPID'
. Se você simplesmente colocar isso em uma planície( … )
, pode parecer que não funciona, pois o seu shell otimizou o garfo. Tente comandos extras no-op( : ; sh -c 'echo $PPID'; : )
para fazê-lo pensar que o subshell é muito complicado para otimizar. O crédito vai para John1024 no Stack Overflow para essa abordagem.fonte
(sh -c 'echo $PPID'; : )
- veja meu comentário na resposta de John1024 .Que tal
BASH_SUBSHELL
?fonte
[isso deveria ter sido um comentário, mas meus comentários tendem a ser excluídos pelos moderadores; portanto, isso permanecerá como uma resposta que eu poderia usar como referência, mesmo se excluído]
O uso não
BASH_SUBSHELL
é totalmente confiável, pois só pode ser definido como 1 em alguns subconjuntos, não em todos os subconjuntos.Antes de afirmar que o subprocesso em que um comando de pipeline é executado não é um subshell realmente real, considere este
man bash
trecho:e as implicações práticas - é se um fragmento de script é executado em um subprocesso ou não, o que é essencial, e não uma queixa de terminologia.
A única solução, como já explicado nas respostas a esta pergunta, é verificar se
$BASHPID
é igual$$
ou, de maneira portável mas muito menos eficiente:fonte
BASH_SUBSHELL
está definido de maneira bastante confiável, mas obter seu valor corretamente é duvidoso. Observe o que os documentos dizem: "Incrementado por um em cada ambiente de subshell ou subshell quando o shell começa a ser executado nesse ambiente. " Acho que no exemplo de pipe, o bash ainda não começou a executar nesse subshell quando a variável é expandida. Você pode compararecho $BASH_VERSION
comdeclare -p BASH_VERSION
- este último deve confiantemente saída 1 com tubos, trabalhos de fundo, etc.eval 'echo $BASH_SUBSHELL $BASHPID' | cat
produzirá 1 paraBASH_SUBSHELL
, porque a variável é expandida após o início da execução.subshell_level
realmente é adiado no caso de pipelines em primeiro plano , o que provavelmente tem algum motivo, mas que não sou capaz de entender ;-)echo $$ $BASHPID $BASH_SUBSHELL | cat
.