ubuntuusers.de

Dateien in tar-Archive verschieben & Src gleichezeitig löschen

Status: Ungelöst | Ubuntu-Version: Server 12.04 (Precise Pangolin)
Antworten |

ziphyx

Anmeldungsdatum:
6. Juni 2012

Beiträge: 2

Hallo,

könnt ihr mir bei folgendem Problem helfen? Ich habe 20GB an Daten (die Rekursiv verstreut in vielen Unterordnern) in einem Hauptordner stecken. Diese Daten möchte ich nun in ein tar-Archiv überführen. Das Problem bei der Sache ist, dass ich nur noch 3GB frei habe. Das bedeutet ich müsste die Dateien alle einzeln ins Archiv kopieren und danach sofort die Quell-Datei löschen, damit der Speicherplatz wieder freigegeben wird. Habt ihr eine Idee, wie solch ein Shellscript aussehen muss, welches diese Arbeit erledigt?

Viele Grüße ziphyx

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13208

ziphyx schrieb:

Hallo,

Herzlich willkommen bei ubuntuusers.de!

könnt ihr mir bei folgendem Problem helfen?

Bestimmt.

Ich habe 20GB an Daten (die Rekursiv verstreut in vielen Unterordnern) in einem Hauptordner stecken. Diese Daten möchte ich nun in ein tar-Archiv überführen. Das Problem bei der Sache ist, dass ich nur noch 3GB frei habe. Das bedeutet ich müsste die Dateien alle einzeln ins Archiv kopieren und danach sofort die Quell-Datei löschen, damit der Speicherplatz wieder freigegeben wird. Habt ihr eine Idee, wie solch ein Shellscript aussehen muss, welches diese Arbeit erledigt?

Möglicherweise kannst Du das direkt mit tar machen, denn das kennt die Option "--remove-files":

1
2
3
4
5
6
7
# direkt finden
$ find ... | tar czvf backup.tgz -T - --remove-files

# zwei Schritte
$ find .... >dateiliste.txt
# hier ggf. die Datei noch bearbeiten
$ tar czvf backup.tgz -T dateiliste.txt --remove-files

Wenn das Archiv nicht komprimiert sein soll, dann kannst "czvf" nach "cvf" ändern. Für noch bessere Komprimierung "czfv" → "cjvf".

Das Programm zip hat auch eine Option "--move", die dasselbe bewirkt, aber die Beschreibung sieht eher so aus, dass das Löschen erst nach komplettem Erstellen des Archivs passiert. Das hilft Dir nicht.

Ansonsten: leih Dir eine USB-Disk und benutze Die als Zwischenspeicher. Ist allemal sicherer. 😉

Ciao

robert

snafu1

Avatar von snafu1

Anmeldungsdatum:
5. September 2007

Beiträge: 2133

Wohnort: Gelsenkirchen

Zum rekursiven Finden von Pfadnamen empfiehlt sich find dein_ordner. Mit find dein_ordner -type f erhälst du nur die Dateien. find kann zudem Befehle auf jede Fundstelle ausführen. So nach diesem Schema:

find dein_ordner -type f -exec echo "Datei gefunden: {}" \; 

{} steht für den gefundenen Pfad. \; ist notwendig, damit find weiß, dass die Anweisung für -exec zu Ende ist.

echo ersetzt du natürlich durch deinen Befehl. Falls du eine Funktion verwendest (sinnvoll bei mehreren Befehlen), dann kannst du sie mittels export -f funktionsname bekannt machen machen und in find wieder über den Funktionsnamen erreichen (siehe http://unix.derkeiler.com/Newsgroups/comp.unix.shell/2007-05/msg00689.html).

Hoffe, das reicht für den Anfang. ☺

EDIT: Kann auch sein, dass man Befehlgruppen geklammert übergeben kann. Hab ich jetzt nicht probiert. Falls dein Komprimiertool eine Option zum Löschen enthält (wie vom Vorposter gezeigt), dann würde ich sowieso eher diese nehmen.

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13208

snafu1 schrieb:

Zum rekursiven Finden von Pfadnamen empfiehlt sich find dein_ordner. Mit find dein_ordner -type f erhälst du nur die Dateien. find kann zudem Befehle auf jede Fundstelle ausführen. So nach diesem Schema:

find dein_ordner -type f -exec echo "Datei gefunden: {}" \; 

{} steht für den gefundenen Pfad. \; ist notwendig, damit find weiß, dass die Anweisung für -exec zu Ende ist.

Guter Punkt, das zu erklären!

echo ersetzt du natürlich durch deinen Befehl. Falls du eine Funktion verwendest (sinnvoll bei mehreren Befehlen), dann kannst du sie mittel export -f funktionsname bekannt machen machen und in find wieder über den Funktionsnamen erreichen.

Das geht nicht so einfach, weil find keine Shell ausführt:

1
2
3
4
5
6
$ foo() { echo "FOO: $*"; }
$ export -f foo
$ bash -c 'foo 1 2 3'
FOO: 1 2 3
$ find lib -exec foo {} +
find: `foo': No such file or directory

Als bessere Alternative zu meiner vorherigen Lösung sollte man tar r mit "--remove-files" kombinieren und als -exec ausführen, denn das tar kann mehrfach aufgerufen werden und dann möchte man die Archive ja nicht überschreiben:

1
2
3
4
# direkt
$ find basis -type f -iname '*.jpg' -exec tar rvf backup.tar --remove-files {} +
# mit xargs, damit man die Anzahl der Argumente (= Dateinamen) für tar kontrollieren kann, hier 123
$ find basis -type f -iname '*.jpg' -print0 | xargs -r0 -n 123 tar rvf backup.tar --remove-files

Ciao

robert

snafu1

Avatar von snafu1

Anmeldungsdatum:
5. September 2007

Beiträge: 2133

Wohnort: Gelsenkirchen

Vielleicht noch der Hinweis, dass -exec in Verbindung mit + die gefundenen Pfade in einem Rutsch an das übergebene Kommando hängt. Das sorgt einerseits dafür, dass der Befehl (hier: tar) nur einmal aufgerufen wird (anstatt für jede Fundstelle einzeln). Andererseits aber kann es dazu führen, dass die Dateien auch erst ganz am Ende wieder gelöscht werden. Da muss man die Doku seines Packtools genau studieren. Wenn tar immer direkt nach dem Packen einer Datei löscht, ist das natürlich gut. Ich wollt nur drauf hingewiesen haben. ☺

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13208

snafu1 schrieb:

Vielleicht noch der Hinweis, dass -exec in Verbindung mit + die gefundenen Pfade in einem Rutsch an das übergebene Kommando hängt. Das sorgt einerseits dafür, dass der Befehl (hier: tar) nur einmal aufgerufen wird (anstatt für jede Fundstelle einzeln).

Nochmal, tar wird seltener aufgerufen als wenn man statt "+" "\;" verwendet, aber es ist nicht garantiert, dass es genau ein Mal aufgerufen wird! Das muss man berücksichtigen. Deshalb meine Anmerkung mit dem "r" statt "c". Mach Dir mal den Spaß und führe folgendes auf Deinem System aus:

1
find / -exec dash -c 'echo $#' -- {} + 2>/dev/null | awk 'BEGIN {s=c=0} { s+=$1;c+=1 } END {print s, c, s/c}'

Dann siehst Du, wie oft find tatsächlich forkt und wie viele Argumente bei jedem Aufruf übergeben werden. Bei mir kommt dabei heraus

377178 161 2342.72

Man sieht, es sind 161 Aufrufe mit durchschnittlich ungefähr 2342 Dateinamen pro Aufruf.

Andererseits aber kann es dazu führen, dass die Dateien auch erst ganz am Ende wieder gelöscht werden. Da muss man die Doku seines Packtools genau studieren. Wenn tar immer direkt nach dem Packen einer Datei löscht, ist das natürlich gut. Ich wollt nur drauf hingewiesen haben. ☺

Ich würde es ausprobieren, und wenn es nicht klappt "+" durch "\;" ersetzen. Es muss aber bei tar zwingend "r" statt "c" verwendet werden, weil man sonst am Ende ein Archiv hat, in dem nicht alle Dateien enthalten sind, die gelöscht wurden. 😬

Ciao

robert

ziphyx

(Themenstarter)

Anmeldungsdatum:
6. Juni 2012

Beiträge: 2

Hi!

Erstmal danke für eure viele Mühe! Nun habe ich ein Problem, dass

1
find basis -type f -iname '*.jpg' -print0 | xargs -r0 -n 123 tar rvf backup.tar --remove-files

zwar die Dateien packt, aber die Dateien werden nicht gelöscht, sondern bleiben erhalten 😕

edit: was haltet ihr von dieser Variante? (Werden die Dateien beim Packen gelöscht oder erst hinterher?)

1
tar  --remove-files -czf archiv.tgz  `find test/ -type f -iname '*.jpg'`

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13208

ziphyx schrieb:

Erstmal danke für eure viele Mühe!

Passt scho.

Nun habe ich ein Problem, dass

1
find basis -type f -iname '*.jpg' -print0 | xargs -r0 -n 123 tar rvf backup.tar --remove-files

zwar die Dateien packt, aber die Dateien werden nicht gelöscht, sondern bleiben erhalten 😕

Muss ich mal untersuchen (werde das mal mit inotify prüfen). Melde mich später nochmal.

edit: was haltet ihr von dieser Variante? (Werden die Dateien beim Packen gelöscht oder erst hinterher?)

1
tar  --remove-files -czf archiv.tgz  `find test/ -type f -iname '*.jpg'`

Nichts, denn die ist nicht sicher, was Sonderzeichen in Dateinamen und lange Argumentlisten angeht, und bringt auch keinen Vorteil gegenüber der Variante mit find ... -exec oder find ... -print0 | xargs -r0.

Ciao

robert

Antworten |