Mein Problem (in einem Skript mit #!/bin/sh
) ist wie folgt: Ich versuche, alle Dateien in einem Verzeichnis zu Archivierungszwecken zu überprüfen. Die Prüfsummendatei (in meinem Fall sha1) mit allen Dateinamen sollte sich im selben Verzeichnis befinden. Nehmen wir an, wir haben ein Verzeichnis ~/test
mit Dateien f1
und f2
:.
mkdir ~/test
cd ~/test
echo "hello" > f1
echo "world" > f2
Berechnen Sie nun die Prüfsummen mit
find -maxdepth 1 -type f -printf '%P\n' | xargs shasum
macht genau das, was ich will, listet nur alle Dateien des aktuellen Verzeichnisses auf und berechnet die sha1-Summen (maxdepth kann später geändert werden). Die Ausgabe auf STDOUT ist:
f572d396fae9206628714fb2ce00f72e94f2258f f1
9591818c07e900db7e1e0bc4b884c945e6a61b24 f2
Leider beim Versuch, dies in einer Datei mit zu speichern
find -maxdepth 1 -type f -printf '%P\n' | xargs shasum > sums.sha1
Die resultierende Datei zeigt die Prüfsumme für sich selbst an:
da39a3ee5e6b4b0d3255bfef95601890afd80709 sums.sha1
f572d396fae9206628714fb2ce00f72e94f2258f f1
9591818c07e900db7e1e0bc4b884c945e6a61b24 f2
und schlägt daher zu einem späteren shasum --check
Zeitpunkt aufgrund des offensichtlichen Problems der zusätzlichen Dateimodifikation beim Speichern der letzten Summe fehl .
Ich habe mich umgesehen und mithilfe von -p
flag for xargs
herausgefunden, dass die Ausgabedatei irgendwie erstellt wird, bevor der Befehl find ausgeführt wird. Daher wird die zusätzliche Datei gefunden und mit einer Prüfsumme versehen ...
Ich weiß, dass ich als Problemumgehung die Prüfsumme an einem anderen Ort speichern könnte (temporäres Verzeichnis über mktemp
) oder sie in find spezifisch ausschließen könnte, aber ich würde gerne verstehen, warum sie sich so verhält, wie sie sich verhält - was in meinen Augen nicht so nützlich ist. Wenn der erste Befehl beispielsweise prüfen würde, ob sich die Ausgabedatei bereits auf der Festplatte befindet, würde er niemals die richtige Antwort erhalten ...
xargs
, dass die Shell selbst diese Datei erstellt, da die Shell vor der Ausführung eines Befehls zunächst alle Eingaben, Ausgaben und Pipes umleitet, sodassfind
die Ausgabedatei beim Start bereits vorhanden ist. Verwenden Sie-exec
stattdessen:find -maxdepth 1 -type f -exec sh -c 'shasum "$@" > sums.sha1' {} +
sh
erforderlich sind. Beachten Sie, dass Sie ein Argument benötigen für$0
vor{}
.tee
ist verschwunden? Ich habe es versucht und es funktioniert gut, ich habe auch STDOUT mit dem Hinzufügen von unterdrückt1>/dev/null
. War etwas mit der Antwort nicht in Ordnung oder war es ein Fehler?Antworten:
Sie können verhindern, dass die Datei erreicht wird,
xargs
indem Sie:Um Probleme mit Dateinamen zu vermeiden, die Leerzeichen oder Zeilenumbrüche oder Anführungszeichen oder Backslashes enthalten, würde ich jedoch Folgendes verwenden:
stattdessen.
Dies
--
dient dazu, Probleme mit Dateinamen zu vermeiden, die mit beginnen-
. Es hilft jedoch nicht für eine aufgerufene Datei-
. Hätten Sie-print0
stattdessen verwendet-printf '%P\0'
, hätten Sie das nicht benötigt--
und hätten kein Problem mit der-
Datei gehabt .quelle
basename
den Dateinamen sums.sha1 aus dem angegebenen vollständigen Pfad abgerufen (dies war nicht in der Frage enthalten, könnte aber anderen helfen).Da Sie verwenden
-maxdepth 1
, gehe ich davon aus, dass Sie keine Rekursion möchten. Wenn ja, machen Sie es stattdessen einfach in der Shell:So überspringen Sie Verzeichnisse:
Wenn Sie eine Rekursion benötigen und verwenden
bash
, gehen Sie wie folgt vor :Beachten Sie, dass alle diese Ansätze den Vorteil haben, an beliebigen Dateinamen zu arbeiten, einschließlich solcher mit Leerzeichen, Zeilenumbrüchen oder anderen Elementen.
quelle
sums.sha1
bereits vorhanden ist (aus einem früheren Lauf), wird es von Ihrer Lösung integriert.sh
, aber Ihre Antwort könnte anderen helfen.mit
zsh
:Der Glob wird vor der Umleitung erweitert, sodass der Glob
sums.sha1
nicht berücksichtigt wird, wenn er überhaupt nicht vorhanden war.D
ist, Punkt-Dateien (versteckte Dateien) wiefind
zu enthalten..
ist, nur reguläre Dateien (wie Ihre-type f
) auszuwählen .Um das
sums.sha1
trotzdem auszuschließen, falls es überhaupt da war:Beachten Sie, dass diese einen Shasum-Befehl ausführen, sodass bei einer großen Liste möglicherweise der Fehler "Arg-Liste zu lang" angezeigt wird. Um das zu umgehen:
Ich würde empfehlen,
./*
anstatt*
zu verwenden, um mögliche Probleme mit einer aufgerufenen Datei zu vermeiden-
.quelle
Wie in den anderen Antworten bereits erwähnt, besteht das Problem darin, dass die Shell die
sums.sha1
Datei öffnet und erstellt , bevor Sie Ihre Pipeline ausführen. Sie können das Programm verwenden,sponge
das Teil desmoreutils
Pakets vieler Distributionen ist. Im Gegensatz zur Shellsponge
wird die Umleitung warten, bis alles empfangen wurde, bevor die Datei geöffnet wird. Es wird im Allgemeinen verwendet, wenn Sie eine Datei schreiben möchten, die Sie in derselben Pipeline gelesen haben.In Ihrem Fall wird es folgendermaßen verwendet:
quelle
Als Alternative zu find / xargs usw. möchten Sie möglicherweise sha1deep. Es ist wahrscheinlich in einem anderen Paket - auf meiner Box kommt es im md5deep-Paket.
Wie andere gesagt haben, wird sums.sha1 von der Shell erstellt, noch bevor find gefunden wird. Ein Trick mit
! -name sums.sha1
zufind
wird funktionieren, wie wirdquelle