errexit ( set -e
) é frequentemente sugerido como uma maneira de tornar scripts simples mais robustos. No entanto, é geralmente considerado como uma armadilha horrível por qualquer um que tenha visto como se comporta em scripts mais complexos, em particular com funções. E um problema muito semelhante pode ser visto com subshells. Veja o exemplo a seguir, adaptado do link
(
set -o errexit
false
true
) && echo "OK" || echo "FAILED";
A armadilha aqui é que os shells mostram "OK" e não "FAILED". [*]
Embora o comportamento de set -e
em casos específicos tenha variado historicamente de forma lamentável, os shells disponíveis em uma distribuição moderna afirmam seguir o padrão de shell POSIX, e os testes mostraram o mesmo comportamento ("OK") para todos os seguintes :
-
bash-4.4.19-2.fc28.x86_64
(Fedora)
-
busybox-1.26.2-3.fc27.x86_64
(Fedora)
-
dash 0.5.8-2.4
(Debian 9)
-
zsh 5.3.1-4+b2
(Debian 9)
-
posh 0.12.6+b1
(Debian 9)
-
ksh 93u+20120801-3.1
(Debian 9).
Pergunta
-
Existe alguma razão técnica pela qual você não pode escrever um shell com recursos semelhantes ao POSIX sh
, exceto que ele imprime FAILED
para o código acima?
Espero que isso também altere set -e
, de modo que as expressões &&
de nível superior que retornam false sejam consideradas fatais. link E esperamos que tenha um idioma melhor para usar com o grep.
set -e
# print matching lines, but it's not an error if there are no matches in the file
(
set +e
grep pattern file.txt
RET=$?
[[ $RET == 0 || $RET == 1 ]] || exit $RET
)
Eu também suponho que as declarações aritméticas ( let
builtin) seriam redefinidas de alguma forma que evita implicitamente coagir seu valor numérico para um status de saída verdadeiro / falso.
-
Existe um exemplo de shell que faz isso?
Eu não me importo de olhar para algo com uma sintaxe diferente de Bourne. Estou interessado em algo que seja compacto, ao escrever scripts curtos de "cola", mas que também tenha uma estratégia compacta para detectar erros. Eu não gosto de usar &&
como um separador de instrução, se isso significa acidentalmente omitir um separador de instrução fará com que os erros sejam ignorados silenciosamente.
[*] EDITAR Este talvez não seja um exemplo perfeito para usar. A discussão sugere que um exemplo melhor seria mover o set -o errexit
acima da subcamada.
AFAICT isto é muito semelhante ao caso de teste (false; echo foo) || echo bar; echo \ $?
da tabela aqui , que diz que mostraria "foo" (e depois "0") no shell Bourne original e na maioria de seus descendentes. As exceções são "hist.ash" e bash 1.14.7.
Quando você adiciona set -e
dentro da subshell - (set -e; false; echo foo) || echo bar; echo \ $?
- há duas exceções adicionais, "SVR4 sh sun5.10" e dash-0.3.4.
Para o espírito da minha pergunta, suponho que ter set -e
dentro da subcamada fosse uma distração. Meu principal interesse é em um idioma onde você usa set -e
no topo do script, e também se aplica a subshells (que já é o comportamento do POSIX).
Jörg Schilling sugere que o shell Bourne do Unix original imprimiria "FAILED" para o exemplo que usei nesta pergunta, que ele portou esse shell para POSIX como "osh "em schilytools , e que este resultado foi verificado a partir do release 2018-06-11. Talvez isso seja baseado em 1) set -e
estando dentro da subcamada e 2) "SVR4 sh sun5.10". "osh" é "baseado nas fontes do OpenSolaris e, portanto, baseado em SVR4 e SVID3". Ou talvez haja alguma variação adicional horrível causada pela adição de && echo "OK"
entre o subshell e o || echo "FAILED"
.
Eu não acho que a shell schily responda a minha pergunta. Você poderia usar subshells para funções (usar (
no lugar de {
para executar a função em um subshell) e iniciar cada subshell com set -e
. No entanto, o uso de subshells apresenta a limitação de que você não pode modificar variáveis globais. Pelo menos, ainda não vi ninguém defender isso como um estilo de codificação de propósito geral.