tar
kann das nicht, aber Sie können erreichen, was Sie wollen mit:
find dir1 -depth -print0 | xargs -0 tar --create --no-recursion --remove-file --file - | bzip2 > dir1.tar.bz2
woher:
find dir1 -depth -print0
listet alle Dateien und Verzeichnisse auf
dir1
und listet den Inhalt des Verzeichnisses vor dem Verzeichnis auf (-depth
). Die Verwendung von-print0
(und-0
in weiterxargs
unten) ist der Schlüssel für Verzeichnis- und Dateinamen mit eingebetteten Leerzeichen unterstützt .xargs -0 tar --create --no-recursion --remove-file --file -
erstellt ein tar-Archiv und fügt jede Datei oder jedes Verzeichnis hinzu. Das tar-Archiv wird mit der Option an die Standardausgabe gesendet
--file -
.bzip2 > dir1.tar.bz2
komprimiert das tar-Archiv von der Standardeingabe in eine Datei namens
dir1.tar.bz2
.
Der benötigte freie Speicherplatz ist die Größe der größten komprimierten Datei in,dir1
da tar
bei der Verarbeitung einer Datei gewartet wird, bis die Archivierung abgeschlossen ist, bevor sie gelöscht wird. Da tar
ist zum Ausleiten bzip2
, für einen kurzen Moment, bevor tar
entfernt, es jede Datei in zwei Orten befindet: unkomprimiert im Dateisystem und in komprimierten dir1.tar.bz2
.
Ich war neugierig, wie der Festplattenspeicher genutzt wurde, also machte ich dieses Experiment auf meiner Ubuntu-VM:
Erstellen Sie ein Dateisystem mit 1 GB:
$ dd if=/dev/zero of=/tmp/1gb bs=1M count=1024 $ losetup /dev/loop0 /tmp/1gb $ mkfs.ext3 /dev/loop0 $ sudo mount /dev/loop0 /tmp/mnt $ df -h Filesystem Size Used Avail Use% Mounted on /dev/loop0 1008M 34M 924M 4% /tmp/mnt
Füllen Sie das Dateisystem mit 900 1-Megabyte-Dateien:
$ chown jaume /tmp/mnt $ mkdir /tmp/mnt/dir1 $ for (( i=0; i<900; i++ )); do dd if=/dev/urandom of=/tmp/mnt/dir1/file$i bs=1M count=1; done $ chown -R jaume /tmp/mnt $ df -h Filesystem Size Used Avail Use% Mounted on /dev/loop0 1008M 937M 20M 98% /tmp/mnt
Das Dateisystem ist jetzt zu 98% belegt.
Kopie
dir1
für spätere Überprüfung erstellen:$ cp -a /tmp/mnt/dir1 /tmp/dir1-check
Komprimieren
dir1
:$ ls /tmp/mnt dir1 lost+found $ find /tmp/mnt/dir1 -depth -print0 | xargs -0 tar --create --no-recursion --remove-file --file - | bzip2 > /tmp/mnt/dir1.tar.bz2 $
Beachten Sie, dass die Befehle ohne Fehler auf dem Gerät ausgeführt wurden.
dir1
wurde entfernt,dir1.tar.bz2
existiert nur :$ ls /tmp/mnt dir1.tar.bz2 lost+found
Erweitern
dir1.tar.bz2
und vergleichen mit/tmp/dir1-check
:$ tar --extract --file dir1.tar.bz2 --bzip2 --directory /tmp $ diff -s /tmp/dir1 /tmp/dir1-check (...) Files /tmp/dir1/file97 and /tmp/dir1-check/file97 are identical Files /tmp/dir1/file98 and /tmp/dir1-check/file98 are identical Files /tmp/dir1/file99 and /tmp/dir1-check/file99 are identical $
Kopie
dir1
und unkomprimiertdir1.tar.bz2
sind identisch!
Dies kann in einem Skript verallgemeinert werden:
Erstellen Sie eine Datei mit dem folgenden Namen
tarrm
(oder einem beliebigen anderen Namen) mit folgendem Inhalt:#!/bin/bash # This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. # This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. # You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. # dir is first argument dir="$1" # check dir exists if [ ! -d "$dir" ]; then echo "$(basename $0): error: '$dir' doesn't exist" 1>&2 exit 1 fi # check if tar file exists if [ -f "$.tar" -o -f "$.tar.bz2" ]; then echo "$(basename $0): error: '$dir.tar' or '$.tar.bz2' already exist" 1>&2 exit 1 fi # --keep is second argument if [ "X$2" == "X--keep" ]; then # keep mode removefile="" echo " Tarring '$dir'" else removefile="--remove-file" echo " Tarring and **deleting** '$dir'" fi # normalize directory name (for example, /home/jaume//// is a legal directory name, but will break $.tar.bz2 - it needs to be converted to /home/jaume) dir=$(dirname "$dir")/$(basename "$dir") # create compressed tar archive and delete files after adding them to it find "$dir" -depth -print0 | xargs -0 tar --create --no-recursion $removefile --file - | bzip2 > "$.tar.bz2" # return status of last executed command if [ $? -ne 0 ]; then echo "$(basename $0): error while creating '$.tar.bz2'" 1>&2 fi
Mach es ausführbar:
chmod a+x tarrm
Das Skript führt einige grundlegende Fehlerüberprüfungen aus: Es dir1
muss vorhanden sein dir1.tar.bz2
und dir1.tar
sollte nicht vorhanden sein und verfügt über einen Keep- Modus. Es unterstützt auch Verzeichnis- und Dateinamen mit eingebetteten Leerzeichen.
Ich habe das Skript getestet, kann aber nicht garantieren, dass es fehlerlos ist. Verwenden Sie es daher zunächst im Keep-Modus:
./tarrm dir1 --keep
Durch diesen Aufruf wird das Verzeichnis hinzugefügt dir1
, dir1.tar.bz2
das Verzeichnis wird jedoch nicht gelöscht.
Wenn Sie dem Skript vertrauen, verwenden Sie es folgendermaßen:
./tarrm dir1
Das Skript informiert Sie darüber, dass dir1
es beim Teering gelöscht wird:
Tarring and **deleting** 'dir1'
Zum Beispiel:
$ ls -lF total 4 drwxrwxr-x 3 jaume jaume 4096 2013-10-11 11:00 dir 1/ $ find "dir 1" dir 1 dir 1/subdir 1 dir 1/subdir 1/file 1 dir 1/file 1 $ /tmp/tarrm dir\ 1/ Tarring and **deleting** 'dir 1/' $ echo $? 0 $ ls -lF total 4 -rw-rw-r-- 1 jaume jaume 181 2013-10-11 11:00 dir 1.tar.bz2 $ tar --list --file dir\ 1.tar.bz2 dir 1/subdir 1/file 1 dir 1/subdir 1/ dir 1/file 1 dir 1/