
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_file
Zeilenichtwird 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? -e
Bash 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 -n1
erzeugt 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 cat
am Ende der Pipe ein hinzufügen. head
unterbricht die Pipe zwar immer noch, da es aber nicht mehr der letzte Befehl darin ist, wird es von nicht berücksichtigt -e
. cat
ist 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 -e
diese 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 echo
ausgeführt!
Es wäre besser, wenn Sie Ihre eigene Fehlerprüfung implementieren würden, -e
das ist nicht die beste Lösung.