
Este script falha às vezes e às vezes é bem-sucedido (uma situação muito chata):
#!/bin/bash
set -Eeuxo pipefail
test_dir="$(mktemp -d)"
touch "$test_dir/file"{001..312}
latest_file="$(find $test_dir -type f | sort -r | head -n1)"
echo $latest_file
Quando tiver sucesso, ele registra algo assim:
++ mktemp -d
+ test_dir=/tmp/tmp.yWelcpBYB7
+ touch /tmp/tmp.yWelcpBYB7/file001 /tmp/tmp.yWelcpBYB7/file002 ... /tmp/tmp.yWelcpBYB7/file312
++ find /tmp/tmp.yWelcpBYB7 -type f
++ head -n1
++ sort -r
+ latest_file=/tmp/tmp.yWelcpBYB7/file312
+ echo /tmp/tmp.yWelcpBYB7/file312
/tmp/tmp.yWelcpBYB7/file312
Quando falha, ele registra algo assim:
++ mktemp -d
+ test_dir=/tmp/tmp.VzTqmgpZyG
+ touch /tmp/tmp.VzTqmgpZyG/file001 /tmp/tmp.VzTqmgpZyG/file002 ... /tmp/tmp.VzTqmgpZyG/file312
++ find /tmp/tmp.VzTqmgpZyG -type f
++ sort -r
++ head -n1
+ latest_file=/tmp/tmp.VzTqmgpZyG/file312
Observe que a echo $latest_file
linha énãoexecutado aqui mesmo que apareça no xtrace
Não consigo executar com êxito se usar 10.000 arquivos, então suspeito que tenha algo a ver comcabeçaparandoencontrarcedo.
#!/bin/bash
set -Eeuxo pipefail
test_dir="$(mktemp -d)"
touch "$test_dir/file"{0000..9999}
latest_file="$(find $test_dir -type f | sort -r | head -n1)"
echo $latest_file
Se eu suprimir stop em caso de erro (usandodefinir +e), ele consegue:
#!/bin/bash
set -Eeuxo pipefail
test_dir="$(mktemp -d)"
touch "$test_dir/file"{0000..9999}
set +e
latest_file="$(find $test_dir -type f | sort -r | head -n1)"
set -e
echo $latest_file
Por que esse script não registra de forma confiável o arquivo mais recente?
Responder1
O problema é o -e
. Por que? -e
faz o bash abortar caso um processo saia com um código de saída diferente de zero (as regras completas são um pouco mais complicadas). Se houver um pipe, apenas o último comando conta.
Você head -n1
cria uma situação de erro, internamente, porque tem que quebrar o cano (você pode verificar isso com strace
) para ignorar o resto da saída de sort
.
Portanto, para fazer seu script funcionar de maneira confiável -e
, você pode adicionar um cat
ao final do canal. head
ainda quebrará o cano, mas como não é mais o último comando nele, não será levado em consideração pelo -e
. cat
é um ambiente autônomo para o tubo:
#!/bin/bash
set -Eeuxo pipefail
test_dir="$(mktemp -d)"
touch "$test_dir/file"{0000..9999}
latest_file="$(find $test_dir -type f | sort -r | head -n1 | cat)"
echo $latest_file
por favor, verifiquePor que set -e (ou set -o errexit ou trap ERR) não faz o que eu esperava?saber por que -e
um recurso tão instável e os tipos de problemas que ele pode causar. Existem muitos exemplos no final. Meu favorito:
#!/bin/bash
set -e
foo=$(expr 1 - 1)
echo survived
Ele vainãoimprimirsobreviveu, essa linha não será executada. Mas, se você tivesse foo=$(expr 2 - 1)
, então o echo
seria executado!
Seria melhor implementar sua própria verificação de erros, -e
não é a melhor solução disponível.