Por que esse script não registra de forma confiável o arquivo mais recente?

Por que esse script não registra de forma confiável o arquivo mais recente?

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_filelinha é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? -efaz 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 -n1cria 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 catao final do canal. headainda 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 -eum 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 echoseria executado!

Seria melhor implementar sua própria verificação de erros, -enão é a melhor solução disponível.

informação relacionada