Warum protokolliert dieses Skript die neueste Datei nicht zuverlässig?

Warum protokolliert dieses Skript die neueste Datei nicht zuverlässig?

Dieses Skript schlägt manchmal fehl und ist manchmal erfolgreich (eine sehr ärgerliche Situation):

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

Bei Erfolg wird etwa Folgendes protokolliert:

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

Bei einem Fehler wird etwa Folgendes protokolliert:

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

Beachten Sie, dass die echo $latest_fileZeilenichtwird hier ausgeführt, obwohl es in xtrace erscheint

Ich kann keinen erfolgreichen Lauf erzielen, wenn ich 10.000 Dateien verwende, also vermute ich, dass es etwas damit zu tun hatKopfStoppenfindenfrüh.

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

Wenn ich den Stopp bei einem Fehler unterdrücke (mitSatz +e), gelingt es:

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

Warum protokolliert dieses Skript die neueste Datei nicht zuverlässig?

Antwort1

Das Problem ist, dass -e. Warum? -eBash abbricht, wenn ein Prozess mit einem Exit-Code ungleich Null beendet wird (die vollständigen Regeln sind etwas komplizierter). Wenn eine Pipe vorhanden ist, zählt nur der letzte Befehl.

Ihr head -n1erzeugt intern eine Fehlersituation, weil es die Pipe sozusagen unterbrechen muss (Sie können dies mit überprüfen strace), um den Rest der Ausgabe von zu ignorieren sort.

Damit Ihr Skript zuverlässig mit funktioniert -e, können Sie catam Ende der Pipe ein hinzufügen. headunterbricht die Pipe zwar immer noch, da es aber nicht mehr der letzte Befehl darin ist, wird es von nicht berücksichtigt -e. catist ein No-Op für die Pipe:

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

überprüfen Sie bitteWarum führt set -e (oder set -o errexit oder trap ERR) nicht zu dem erwarteten Ergebnis?um zu erfahren, warum -ediese Funktion so instabil ist und welche Probleme sie verursachen kann. Am Ende gibt es viele Beispiele. Mein Favorit:

#!/bin/bash

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

Es wirdnichtdruckenüberlebt, wird diese Zeile nicht ausgeführt. Wenn Sie jedoch hätten foo=$(expr 2 - 1), würde die echoausgeführt!

Es wäre besser, wenn Sie Ihre eigene Fehlerprüfung implementieren würden, -edas ist nicht die beste Lösung.

verwandte Informationen