¿Por qué este script no registra de manera confiable el archivo más reciente?

¿Por qué este script no registra de manera confiable el archivo más reciente?

Este script falla a veces y otras veces tiene éxito (una situación muy molesta):

#!/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

Cuando tiene éxito, registra algo como esto:

++ 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

Cuando falla, registra algo como esto:

++ 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 la echo $latest_filelínea esnoejecutado aquí aunque aparece en xtrace

No puedo ejecutar correctamente si uso 10.000 archivos, por lo que sospecho que tiene algo que ver concabezaparadaencontrartemprano.

#!/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

Si suprimo la parada por error (usandoconjunto +e), tiene éxito:

#!/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 qué este script no registra de manera confiable el archivo más reciente?

Respuesta1

El problema es el -e. ¿Por qué? -ehace que bash aborte en caso de que un proceso salga con un código de salida distinto de cero (las reglas completas son un poco más complicadas). Si hay una tubería, solo cuenta el último comando.

Crea head -n1una situación de error, internamente, porque tiene que romper la tubería (puede comprobarlo con strace) para ignorar el resto de la salida sort.

Entonces, para que su script funcione de manera confiable -e, puede agregar a catal final de la tubería. headSeguirá rompiendo la tubería, pero como ya no es el último comando, no será tenido en cuenta por -e. cates una operación no operativa para la tubería:

#!/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, compruebe¿Por qué set -e (o set -o errexit o trap ERR) no hace lo que esperaba?saber por qué -ees una característica tan inestable y el tipo de problemas que puede provocar. Hay muchos ejemplos al final. Mi favorito:

#!/bin/bash

set -e
foo=$(expr 1 - 1)
echo survived

Va anoimprimirsobrevivió, esa línea no se ejecutará. Pero, si lo hubieras hecho foo=$(expr 2 - 1), ¡ echosería ejecutado!

Sería mejor que implementara su propia verificación de errores, -eno es la mejor solución que existe.

información relacionada