Estoy tratando de escribir una función para reemplazar la funcionalidad del exit
incorporado para evitar que salga del terminal.
Intenté usar la SHLVL
variable de entorno pero no parece cambiar dentro de las subcapas:
$ echo $SHLVL
1
$ ( echo $SHLVL )
1
$ bash -c 'echo $SHLVL'
2
Mi función es la siguiente:
exit () {
if [[ $SHLVL -eq 1 ]]; then
printf '%s\n' "Nice try!" >&2
else
command exit
fi
}
Sin exit
embargo, esto no me permitirá usar dentro de subcapas:
$ exit
Nice try!
$ (exit)
Nice try!
¿Cuál es un buen método para detectar si estoy o no en una subshell?
(...)
heredan todas las propiedades del proceso primario. Las respuestas proporcionadas son soluciones más sólidas para determinar su nivel de shell.BASH_SUBSHELL
respuesta (aunque controvertida) no se aplicaría a esa pregunta.Respuestas:
En bash, puedes comparar
$BASHPID
a$$
Si no está en bash,
$$
debería permanecer igual en una subshell, por lo que necesitaría alguna otra forma de obtener su ID de proceso real.Una forma de obtener su pid real es
sh -c 'echo $PPID'
. Si lo pone en un plano( … )
, puede parecer que no funciona, ya que su caparazón ha optimizado el tenedor. Pruebe comandos adicionales sin operación( : ; sh -c 'echo $PPID'; : )
para que piense que la subshell es demasiado complicada para optimizarla. El crédito va a John1024 en Stack Overflow para ese enfoque.fuente
(sh -c 'echo $PPID'; : )
- vea mi comentario sobre la respuesta de John1024 .¿Qué tal
BASH_SUBSHELL
?fuente
[Esto debería haber sido un comentario, pero mis moderadores tienden a eliminar mis comentarios, por lo que esto quedará como una respuesta que podría usar como referencia incluso si se elimina]
El uso
BASH_SUBSHELL
es completamente poco confiable ya que solo se establece en 1 en algunas subcapas, no en todas las subcapas.Antes de afirmar que el subproceso en el que se ejecuta un comando de canalización no es una subshell realmente real, considere este
man bash
fragmento:y las implicaciones prácticas: es esencial si un fragmento de secuencia de comandos se ejecuta en un subproceso o no, no una objeción terminológica.
La única solución, como ya se explicó en las respuestas a esta pregunta, es verificar si
$BASHPID
es igual$$
o, de manera portátil pero mucho menos eficiente:fuente
BASH_SUBSHELL
se establece de manera bastante confiable, pero obtener su valor correctamente es dudoso. Tenga en cuenta lo que dicen los documentos : "Incrementado en uno dentro de cada entorno de subshell o subshell cuando el shell comienza a ejecutarse en ese entorno " . Creo que en el ejemplo de tubería, bash aún no ha comenzado a ejecutarse en ese subshell cuando la variable se expande. Puede compararecho $BASH_VERSION
condeclare -p BASH_VERSION
- este último debe generar de manera confiable 1 con tuberías, trabajos en segundo plano, etc.eval 'echo $BASH_SUBSHELL $BASHPID' | cat
generará 1 paraBASH_SUBSHELL
, porque la variable se expande después de que la ejecución ha comenzado.subshell_level
realmente se difiere en el caso de las tuberías en primer plano , lo que probablemente tenga alguna razón, pero que no puedo distinguir ;-)echo $$ $BASHPID $BASH_SUBSHELL | cat
.