set -u use não está funcionando conforme o esperado

12

Estou aprendendo a usar com eficiência diferentes setopções no meu script e deparei-me set -uque parece ser perfeito para sair do meu script se uma variável não for definida corretamente (por exemplo, excluindo usuários). De acordo com a página do manual , set -ue set -efaz o seguinte ...

-e  Exit immediately if a command exits with a non-zero status.
-u  Treat unset variables as an error when substituting.

Criei um script de teste para testar essa funcionalidade, mas ela não parece estar funcionando conforme o esperado. Talvez alguém possa me explicar melhor o meu problema e onde estou interpretando mal? O script de teste está abaixo. Obrigado.

set -e
set -u
testing="This works"
echo $?
echo ${testing}
testing2=
echo $?
echo ${testing2}
testing3="This should not appear"
echo $?
echo ${testing3}

Espero que o script exiba 0 e "Isso funcione" e falhe, pois ${testing2}não está definido.

Em vez disso, são exibidos 0 e "Isso funciona" , seguido por 0 e, em seguida, 0 Isso não deve aparecer

Alguém pode fornecer algum conhecimento? Obrigado.

Azifor
fonte
1
Portanto, o acompanhamento ... existe alguma maneira de tornar ilegal a configuração de uma variável para a cadeia nula / gerar um erro? Acho que não.
Luke Davis

Respostas:

10

De "homem Bash":

Um parâmetro é definido se tiver sido atribuído um valor. A cadeia nula é um valor válido. Depois que uma variável é definida, ela pode ser desabilitada apenas usando o comando embutido desabilitado.

Quando você testing2=define a variável como uma seqüência nula.

Mude isso para unset testing2e tente novamente.


A set -enão ajuda neste caso como uma atribuição não tem um código de saída 1. Tente isto para ver que o último comando executado (a atribuição) tem um código de saída de 0, ou ler esta pergunta :

$ false; a=""; echo $?
0

E também acredito que o uso de set -e é mais um problema do que uma solução.

O que pode receber um erro com o uso de variáveis ​​não definidas é set -u:

#!/bin/bash
set -u
testing="This works"
echo ${testing}
unset testing2
echo ${testing2}
testing3="This should not appear"
echo ${testing3}

Saída:

$  ./script.sh
This works
./script.sh: line 9: testing2: unbound variable
Comunidade
fonte
3

testing2=define a testing2variável como uma sequência vazia; a variável realmente está definida .

No entanto, se você executasse echo $testing99um shell Bash interativo (sem configuração errexit, por exemplo, set -e), você receberia um erro:

bash: testing99: unbound variable

a parte, de lado

Ao testar scripts agora, descobri que um shell interativo nem sempre sai ao tentar expandir uma variável que não foi definida enquanto um shell não interativo (executando um script de shell) sempre sai . De acordo com a página do manual POSIX para set:

-u O shell deve escrever uma mensagem para erro padrão quando tenta expandir uma variável que não está definida e sair imediatamente. Um shell interativo não deve sair.

Um shell Bash interativo não será fechado, a menos errexitque também tenha sido definido. Por outro lado, um shell de traço interativo não sai - mesmo se set -ejá tiver sido executado anteriormente.

Anthony Geoghegan
fonte
Se o traço não sair com set -e; set -u; desabilitar aa; eco $ aa, então o traço está errado.
schily
@schily Quando percebi isso pela primeira vez, percebi que os autores do traço sabiam melhor do que eu e que talvez houvesse alguma ambiguidade nas especificações do POSIX, mas depois de verificar novamente pubs.opengroup.org/onlinepubs/9699919799/utilities/… , I Concordo que parece um bug, tudo bem.
Anthony Geoghegan
Existe uma regra simples: quando o Korn Shell e o Bourne Shell concordam e outra implementação do shell tem um desvio, o outro shell se comporta incorretamente.
schily 9/16