
Tengo una función y me gustaría usar la pipefail
opción interna. Pero no quiero simplemente hacerlo set -o pipefail
, porque temo que otra parte del guión no espere pipefail
estar ambientada. Por supuesto que podría hacerlo set +o pipefail
después, pero en caso de que pipefail
se establezca fuera de mi función, esto también puede introducir un comportamiento inesperado.
Por supuesto, podría usar el código de salida false | true
como medida, si pipefail
está configurado, pero esto parece un poco sucio.
¿Existe una forma más general (y tal vez canónica?) de verificar las opciones configuradas de bash?
Respuesta1
En bash-4.4
y superiores, puedes usar:
myfunction() {
local -
set -o someoption
...
}
Algunas notas:
- eso está copiado de
ash
. Enash
, la idea es hacer$-
(que almacena el conjunto de opciones) local. Funcionaash
porque enash
,local
no afecta el valor ni los atributos de la variable (al contrario debash
donde inicialmente la desarma). Aún así, también funciona debash
la misma manera que enash
un caso especial, es decir, no hace que$-
se desarme ni vuelva a un comportamiento predeterminado. - solo cubre las opciones establecidas con
set -o option
, no las establecidas porshopt -s option
(bash
¡siendo el único shell con dos conjuntos de opciones!) Al igual que con las variables locales, es un alcance dinámico, no estático. El valor de
$-
se restaurará al regresar de la función, pero la nueva configuración afectará a las otras funciones o scripts de origen llamados por su función. Si desea un alcance estático, deberá cambiar a ksh93 y usar:function myfunction { set -o myoption ... other_function }
Con el
other_function
no afectado siempre que se declarefunction other_function {
también con la sintaxis (y no con laother_function()...
sintaxis de Bourne).Como no restablece las opciones, su función aún puede verse afectada por las opciones establecidas por otro código. Para evitar eso, querrás usarlo
zsh
en su lugar.zsh
es el equivalente alocal -
esset -o localoptions
, pero también puedes llegar a un conocidoemulaciónmodoen la zona. Por ejemplo:myfunction() { emulate -L zsh set -o someoption ... }
comenzaría con un conjunto de opciones zsh-default sensato (con algunas excepciones, consulte el documento) encima del cual agregaría su opción. Eso también es alcance dinámico como en ash/bash, pero también puedes llamar a otras funciones con:
emulate zsh -c 'other_function...'
para que eso
other_function
se llame con un conjunto de opciones vanilla zsh.zsh también tiene una serie de operadores que pueden hacer que evite cambiar opciones globalmente en primer lugar (como calificadores
(N)
/(D)
glob paranullglob
/dotglob
,(#i)
operador glob para globalización que no distingue entre mayúsculas y minúsculas,${(s:x:)var}
para evitar mezclarse con$IFS
,${~var}
parapedidoglobbing sobre la expansión de parámetros (necesitanoglob
en otros shells tipo Bourneevitar(!) él)...
Respuesta2
La $SHELLOPTS
variable contiene todas las opciones establecidas separadas por dos puntos. Como ejemplo, podría verse así:
braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor
Para verificar una opción determinada, se puede hacer lo siguiente:
# check if pipefail is set, if not set it and remember this
if [[ ! "$SHELLOPTS" =~ "pipefail" ]]; then
set -o pipefail;
PIPEFAIL=0;
else
PIPEFAIL=1;
fi
# do something here
# reset pipefail, if it was not set before
if [ "$PIPEFAIL" -eq 0 ]; then
set +o pipefail;
fi
Respuesta3
Si desea configurar una opción de shell dentro de una función, pero no desea afectar a la persona que llama, puede hacerlo de dos maneras diferentes:
Opción 1: subcapa
Coloque la función dentro de una subcapa (observe el paréntesis que rodea las declaraciones de la función en lugar de las llaves):
function foo() (
set -o pipefail
echo inside foo
shopt -o pipefail
# ...
)
Entonces, la persona que llama puede tener desarmado el pipefail y no se ve afectado:
$ shopt -o pipefail
pipefail off
$ foo
inside foo
pipefail on
$ shopt -o pipefail
pipefail off
o
Opción 2: probar y restablecer
Puede probar y restablecer la opción según sea necesario (observe las llaves alrededor de las declaraciones de función, sin subcapa):
function foo() {
shopt -q -o pipefail
local resetpipefail=$?
set -o pipefail
echo inside foo
shopt -o pipefail
# ...
# only reset pipefail if needed
[[ $resetpipefail -eq 1 ]] && set +o pipefail
}
$ shopt -o pipefail
pipefail off
$ foo
inside foo
pipefail on
$ shopt -o pipefail
pipefail off
punta de sombrero paracuonglmpara ellosshopt -q
respuesta.
Respuesta4
Usa una trampa de RETORNO
Los comandos especificados con una
RETURN
captura se ejecutan antes de que se reanude la ejecución después de que se ejecute una función de shell o un script de shell con.
osource
regrese.[...]
La-p
opción [comprar] hace que la salida se muestre en un formulario que puede reutilizarse como entrada.
foo() {
trap "$(shopt -p -o pipefail)" RETURN
set -o pipefail
echo inside foo
shopt -o pipefail
# ...
}
Prueba
$ shopt -o pipefail
pipefail off
$ foo
inside foo
pipefail on
$ shopt -o pipefail
pipefail off
La siguiente plantilla de función maneja el caso general de garantizar que ambas opciones set
y shopt
se restablezcan a sus valores originales cuando regresa una función:
foo() {
trap "$(shopt -p -o; shopt -p)" RETURN # ①
# ...
}
① shopt -p -o
se puede simplificar al equivalente estándar set +o
.