Eu li muitas perguntas em vários sites de troca de pilhas e fóruns de ajuda do unix sobre como modificar opções de shell e depois restaurá-las - a mais abrangente que encontrei aqui é em Como "desfazer" um `set -x`?
A sabedoria recebida parece ser a de salvar tanto fora o resultado de set +o
ou shopt -po
e, em seguida, eval
ele mais tarde para restaurar as configurações anteriores.
No entanto, em meus próprios testes com o bash 3.xe 4.x, a errexit
opção não é salva corretamente ao fazer a substituição de comandos.
Aqui está um exemplo de script para mostrar o problema:
set -o errexit
set -o nounset
echo "LOCAL SETTINGS:"
set +o
OLDOPTS=$(set +o)
echo
echo "SAVED SETTINGS:"
echo "$OLDOPTS"
E saída (cortei algumas das variáveis irrelevantes):
LOCAL SETTINGS:
set -o errexit
set -o nounset
SAVED SETTINGS:
set +o errexit
set -o nounset
Isso parece extremamente perigoso. A maioria dos scripts que escrevo depende errexit
para interromper a execução se algum comando falhar. Eu apenas localizei um bug em um dos meus scripts causado por isso, onde a função que deveria restaurar errexit
no final acabou substituindo-a, retornando-a ao padrão de off durante a duração do script.
O que eu gostaria de poder fazer é escrever funções que podem definir opções conforme necessário e depois restaurar todas as opções corretamente antes de sair. Mas parece que no sub-invocador invocado pela substituição de comando, errexit
não é herdado.
Estou sem saber como salvar o resultado set +o
sem usar a substituição de comandos ou pular os aros FIFO. Eu posso ler, $SHELLOPTS
mas não é eval
um formato gravável ou inativável.
Eu sei que uma alternativa é usar uma função subshell , mas isso introduz muitas dores de cabeça por poder registrar a saída e também transmitir várias variáveis.
Provavelmente relacionado: /programming/29532904/bash-subshell-errexit-semantics (parece que existe uma solução alternativa para o bash 4.4 e superior, mas eu prefiro ter uma solução portátil)
shopt
opções de conjunto do bash (como nullglob).Respostas:
O que você está fazendo deve funcionar. Mas o bash desativa a
errexit
opção nas substituições de comando, portanto, preserva todas as opções, exceto esta. Isso é específico para o bash e específico para aerrexit
opção. O Bash preservaerrexit
ao executar no modo POSIX. Desde o bash 4.4, o bash também não limpaerrexit
em uma substituição de comando seshopt -s inherit_errexit
estiver em vigor.Como a opção está desativada antes que qualquer código seja executado dentro da substituição de comando, você deve verificar fora.
Se você não gosta dessa complexidade, use zsh.
fonte
bash4.4
agora temlocal -
(à laash
) como equivalente azsh
'ssetopt localoptions
(ou o que o ksh88 faz por padrão) #shopt -s lastpipe; set +o | IFS= read -rd '' OLDOPTS || :
(os dois conjuntos de opções são outra dasbash
idiossincrasias de).OLDOPTS="$(set +o); set -$-"
.Depois de experimentar o anterior no alpine 3.6, agora adotei a seguinte abordagem muito mais simples:
de acordo com a documentação, "$ -" mantém a lista de opções ativas no momento. Parece funcionar muito bem, estou perdendo alguma coisa?
fonte
set -uf
)errexit
é propagado em substituições de processo.Verifica:
Versão do Bash:
fonte
A solução simples é anexar a
errexit
configuração aOLDOPTS
:Feito.
fonte
[[ -o errexit ]]
(ksh / bash / zsh) e[ -o errexit ]
(bash / ksh / yash)shopt
comando é válido para o bash, não há razão significativa para evitá-lo (eu sou apenas uma questão de sua preferência pessoal de como as respostas devem ser escritas). Não é uma mudança significativa. @ StéphaneChazelas