tar: Datei wurde beim Lesen geändert

76

Ich benutze makeund tarzu sichern. Bei der Ausführung von makefile wird der Befehl tar angezeigt file changed as we read it. In diesem Fall,

  • Das Teerpaket ist in Ordnung, wenn die Warnung angezeigt wird
  • Der Befehl tar für die folgende Sicherung wird jedoch gestoppt
  • Die Datei mit der Warnung ändert sich nicht - es ist wirklich seltsam, dass die Warnung angezeigt wird
  • Die Dateien, in denen die Warnung angezeigt wird, werden zufällig angezeigt. Ich meine, jedes Mal, wenn ich mein Makefile ausführe, sind die Dateien, in denen die Warnung angezeigt wird, unterschiedlich
  • --ignore-failed-readhilft nicht. Ich verwende Teer 1.23 in MinGW
  • Ich habe gerade meinen Computer auf WIN7 64 Bit umgestellt. Das Skript funktioniert gut in alten WIN7 32-Bit. Die Tar-Version ist jedoch nicht so neu wie die 1.23.

Wie kann ich die Warnung des Teers stoppen, um meine Sicherung nach der Warnung zu stoppen?


Edit-2 : Es könnte der Grund sein

Wie ich oben sagte, funktionierte das Bash-Shell-Skript auf meinem alten Computer gut. Im Vergleich zum alten Computer ist die msysVersion anders. So ist die Version des Befehls tar. Auf dem alten Computer ist tar 1.13.19 und auf dem neuen Computer 1.23. Ich habe den alten tar-Befehl kopiert, ohne seine Abhängigkeit msys-1.0.dll auf den neuen Computer zu kopieren, und ihn in tar_old umbenannt. Außerdem habe ich den Befehl tar im Shell-Skript aktualisiert und das Skript ausgeführt. Dann ist alles in Ordnung. Das Problem schien also der Befehl tar zu sein. Ich bin sicher, dass beim Tarieren keine Datei geändert wird. Ist es ein Fehler für den Befehl tar in der neuen Version? Ich weiß es nicht.


Edit-1 : Weitere Details hinzufügen

Die Sicherung wird von einem Bash-Shell-Skript aufgerufen. Es durchsucht das Zielverzeichnis und erstellt ein Makefile. Anschließend wird der Befehl make aufgerufen, um den Befehl tar für die Sicherung zu verwenden. Es folgt ein typisches Makefile, das vom Bash-Shell-Skript erstellt wurde.

#--------------------------------------------
# backup VC
#--------------------------------------------
# the program for packing
PACK_TOOL=tar

# the option for packing tool
PACK_OPTION=cjvf

# M$: C driver
WIN_C_DIR=c:

# M$: D driver
WIN_D_DIR=d:

# M$: where the software is
WIN_PRG_DIR=wuyu/tools
# WIN_PRG_DIR=

# where to save the backup files
BAKDIR=/home/Wu.Y/MS_bak_MSYS

VC_FRAMEWORK=/home/Wu.Y/MS_bak_MSYS/tools/VC/VC_framework.tar.bz2
VC_2010=/home/Wu.Y/MS_bak_MSYS/tools/VC/VC_2010.tar.bz2

.PHONY: all

all: $(VC_FRAMEWORK) $(VC_2010)

$(VC_FRAMEWORK): $(WIN_C_DIR)/$(WIN_PRG_DIR)/VC/Framework/*
    @$(PACK_TOOL) $(PACK_OPTION) "$@" --ignore-failed-read /c/$(WIN_PRG_DIR)/VC/Framework
$(VC_2010): $(WIN_C_DIR)/$(WIN_PRG_DIR)/VC/VS2010/*
    @$(PACK_TOOL) $(PACK_OPTION) "$@" --ignore-failed-read /c/$(WIN_PRG_DIR)/VC/VS2010

Wie Sie sehen können, wird das tar-Paket in ~ / MS_bak_MSYS / tools / VC / VC_2010.tar.bz2 gespeichert. Ich führe das Skript in ~ / qqaa aus. ~/MS_bak_MSYSist vom Befehl tar ausgeschlossen. Die von mir erstellte TAR-Datei befindet sich also nicht in einem Verzeichnis, das ich in die TAR-Datei einfügen möchte. Deshalb fand ich es seltsam, dass die Warnung kam.

warem
quelle
Es sieht so aus, als würden Sie das Windows-Setup verwenden, was für Sie nicht relevant ist. Wir haben jedoch ein ähnliches Problem, wenn das zugrunde liegende Dateisystem glusterfs ist. Es sieht so aus, als ob es einen Fehler gibt, wenn lstat und fstat unterschiedliche Werte zurückgeben: bugzilla.redhat.com/show_bug.cgi?id=1058526
Arie Skliarouk
Ich habe dieses Problem mit tar auf einem von Windows Docker gemounteten Volume. Der Austausch des tarDienstprogramms gegen paxhat für mich funktioniert.
Andreas

Antworten:

75

Ich stoße auch auf die Teermeldungen "geändert, während wir es lesen". Für mich trat diese Meldung auf, als ich eine TAR-Datei des Linux-Dateisystems in einer Bitbake-Build-Umgebung erstellte. Dieser Fehler war sporadisch.

Für mich war dies nicht darauf zurückzuführen, dass eine TAR-Datei aus demselben Verzeichnis erstellt wurde. Ich gehe davon aus, dass während der Erstellung der TAR-Datei tatsächlich eine Datei überschrieben oder geändert wurde.

Die Nachricht ist eine Warnung und erstellt weiterhin die TAR-Datei. Wir können diese Warnmeldung weiterhin unterdrücken, indem wir die Option einstellen

--warning=no-file-changed

( http://www.gnu.org/software/tar/manual/html_section/warnings.html )

Der vom Tar zurückgegebene Exit-Code lautet im Fall einer Warnmeldung weiterhin "1": http://www.gnu.org/software/tar/manual/html_section/Synopsis.html

Wenn wir also die TAR-Datei von einer Funktion in Skripten aus aufrufen, können wir den Exit-Code folgendermaßen behandeln:

set +e 
tar -czf sample.tar.gz dir1 dir2
exitcode=$?

if [ "$exitcode" != "1" ] && [ "$exitcode" != "0" ]; then
    exit $exitcode
fi
set -e
Sandeep
quelle
Ich habe das gleiche Problem und diese Antwort "löste" mein Problem, indem sie mir die Möglichkeit gab, es zu umgehen. Danke @sandeep.
Jaskho
11
Tar beendet mit 1: "Wenn tar die Option" --create "," --append "oder" --update "erhalten hat, bedeutet dieser Exit-Code, dass einige Dateien während der Archivierung geändert wurden und das resultierende Archiv daher nicht das genaue enthält Kopie des Dateisatzes. " Dies ist ein umwerfendes schlechtes Verhalten - es wird eine Pipeline töten und es gibt keine Möglichkeit, sie zu stoppen. Gesichtspalme
Otheus
Hinweis @Otheusset +e
Ryan Brodie
2
@ RyanBrodie Ich dachte nach dem Vorbild von set -o pipefail; tar ... | gzip. Aber ich nehme es zurück; Es wird nicht die gesamte Pipeline beendet, da der Exit bis zum Ende der Ausführung verschoben wird.
Otheus
59

Es ist zwar sehr spät, aber ich hatte vor kurzem das gleiche Problem.

Das Problem ist, dass sich das Verzeichnis .ändert, wenn xyz.tar.gzes nach dem Ausführen des Befehls erstellt wird. Es gibt zwei Lösungen:

Lösung 1: Es macht tar nichts aus, wenn das Archiv in einem beliebigen Verzeichnis erstellt wird .. Es kann Gründe geben, warum das Archiv nicht außerhalb des Arbeitsbereichs erstellt werden kann. Es wurde umgangen, indem ein temporäres Verzeichnis erstellt wurde, in dem das Archiv wie folgt abgelegt wurde:

mkdir artefacts
tar -zcvf artefacts/archive.tar.gz --exclude=./artefacts .
echo $?
0

Lösung 2: Diese mag ich. Erstellen Sie die Archivdatei, bevor Sie tar ausführen:

touch archive.tar.gz
tar --exclude=archive.tar.gz -zcvf archive.tar.gz .
echo $?
0
Mohammad Azim
quelle
6
--exclude=archive.tar.gzStellen -zvcfSie in Lösung 2 einfach die vor die andere Option und es funktioniert tatsächlich gut.
Kaj Kandler
36

Wenn Sie Hilfe beim Debuggen eines solchen Problems benötigen, müssen Sie die make-Regel oder zumindest den von Ihnen aufgerufenen Befehl tar angeben. Wie können wir sehen, was mit dem Befehl nicht stimmt, wenn kein Befehl zu sehen ist?

In 99% der Fälle bedeutet ein solcher Fehler jedoch, dass Sie die TAR-Datei in einem Verzeichnis erstellen, das Sie in die TAR-Datei einfügen möchten. Wenn tar versucht, das Verzeichnis zu lesen, findet es die tar-Datei als Mitglied des Verzeichnisses, beginnt sie zu lesen und in die tar-Datei zu schreiben, und zwar zwischen dem Zeitpunkt, an dem die tar-Datei gelesen wird, und dem Zeitpunkt, an dem sie beendet ist Beim Lesen der TAR-Datei hat sich die TAR-Datei geändert.

Also zum Beispiel so etwas wie:

tar cf ./foo.tar .

Es gibt keine Möglichkeit, dies zu "stoppen", weil es nicht falsch ist. Platzieren Sie Ihre TAR-Datei einfach an einer anderen Stelle, wenn Sie sie erstellen, oder suchen Sie einen anderen Weg (mit --excludeoder was auch immer), um die TAR-Datei wegzulassen.

Verrückter Wissenschaftler
quelle
Ich habe im ursprünglichen Beitrag weitere Details hinzugefügt. Bitte prüfen.
Warem
Aufgrund der Informationen hier weiß ich nicht, was los ist. Ich weiß jedoch sehr wenig über die Arbeit mit Windows oder Cygwin ... Ich weiß, dass es viel schwieriger ist, mit mehreren WRT-Programmen, die auf dieselbe Datei zugreifen , mit einem Windows-Dateisystem zu arbeiten als mit einem POSIX-basierten Dateisystem. Dies scheint jedoch für Ihre Situation nicht unmittelbar relevant zu sein. Alles, was ich vorschlagen kann, ist, das @in Ihren Regeln zu entfernen und den Befehl make zu überprüfen, um sicherzustellen, dass er korrekt ist, und die Dateien zu überprüfen, die tar zu erstellen versucht (Ausgabe mit der Option v), um sicherzustellen, dass nichts Geheimnisvolles vorhanden ist.
MadScientist
18

Hier ist ein Einzeiler zum Ignorieren des Teer-Exit-Status, wenn er 1 ist. Es ist nicht erforderlich, set +ewie im Skript von Sandeep . Wenn der Teer-Exit-Status 0 oder 1 ist, kehrt dieser Einzeiler mit dem Exit-Status 0 zurück. Andernfalls kehrt er mit dem Exit-Status 1 zurück. Dies unterscheidet sich von Sandeeps Skript, bei dem der ursprüngliche Exit-Status-Wert beibehalten wird, wenn er sich von 1 unterscheidet .

tar -czf sample.tar.gz dir1 dir2 || [[ $? -eq 1 ]]

Fabian Ritzmann
quelle
5

Um Fabians Einzeiler zu verbessern; Nehmen wir an, wir möchten nur den Exit-Status 1 ignorieren, aber den Exit-Status beibehalten, wenn es sich um etwas anderes handelt:

tar -czf sample.tar.gz dir1 dir2 || ( export ret=$?; [[ $ret -eq 1 ]] || exit "$ret" )

Dies macht alles, was das Skript von Sandeep macht, in einer Zeile.

Jeremy
quelle
3

Die Verwendung eines äußeren Verzeichnisses für die Ausgabe löste das Problem für mich.

sudo tar czf ./../31OCT18.tar.gz ./
Mohd Abdul Mujib
quelle
1
Wenn Sie den neuen Teer in denselben Ordner legen, den Sie komprimieren, ändert sich lol
Daniel W.
0

Es funktionierte für mich, indem eine einfache Schlafzeit von 20 Sekunden hinzugefügt wurde. Dies kann passieren, wenn Ihr Quellverzeichnis noch schreibt. Legen Sie daher einen Ruhezustand fest, damit die Sicherung beendet wird und Teer dann einwandfrei funktioniert. Dies hat mir auch geholfen, den richtigen Exit-Status zu erhalten.

sleep 20
tar -czf ${DB}.${DATE}.tgz ./${DB}.${DATE}
Ninohead
quelle
0

Ich bin nicht sicher, ob es zu Ihnen passt, aber ich habe festgestellt, dass tardies bei geänderten / gelöschten Dateien im Pipe-Modus nicht fehlschlägt. Verstehst du, was ich meine.

Testskript:

#!/usr/bin/env bash
set -ex
tar cpf - ./files | aws s3 cp - s3://my-bucket/files.tar
echo $?

Manuelles Löschen zufälliger Dateien ...

Ausgabe:

+ aws s3 cp - s3://my-bucket/files.tar
+ tar cpf - ./files
tar: ./files/default_images: File removed before we read it
tar: ./files: file changed as we read it
+ echo 0
0
Pavel Prischepa
quelle
1
Dies liegt daran, dass Exit-Codes innerhalb von Pipes standardmäßig ignoriert werden. Und es ist eine gute Praxis, sie durch "set -o pipefail" wieder zu aktivieren.
Sergey