tar
nie możesz tego zrobić, ale możesz osiągnąć to, co chcesz:
find dir1 -depth -print0 | xargs -0 tar --create --no-recursion --remove-file --file - | bzip2 > dir1.tar.bz2
gdzie:
find dir1 -depth -print0
wyświetla listę wszystkich plików i katalogów dir1
, wyświetlając zawartość katalogu przed samym katalogiem ( -depth
). Zastosowanie -print0
(a -0
w xargs
niżej) jest kluczem do wspierania nazw katalogów i plików ze spacjami .
xargs -0 tar --create --no-recursion --remove-file --file -
tworzy archiwum tar i dodaje do niego każdy plik lub katalog. Archiwum tar jest wysyłane na standardowe wyjście z opcją --file -
.
bzip2 > dir1.tar.bz2
kompresuje archiwum tar ze standardowego wejścia do pliku o nazwie dir1.tar.bz2
.
Wymagana ilość wolnego miejsca na dysku to rozmiar największego skompresowanego pliku,dir1
ponieważ tar
podczas przetwarzania pliku czeka na zakończenie archiwizacji przed usunięciem. Ponieważ tar
jest pobierany bzip2
przez krótki czas, przed jego tar
usunięciem, każdy plik znajduje się w dwóch miejscach: nieskompresowany w systemie plików i skompresowany w środku dir1.tar.bz2
.
Byłem ciekawy, jak wykorzystano miejsce na dysku, więc przeprowadziłem ten eksperyment na mojej maszynie Wirtualnej Ubuntu:
Utwórz system plików 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
Wypełnij system plików 900 1 megabajtowymi plikami:
$ 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
System plików jest teraz w 98% pełny.
Wykonaj kopię dir1
do późniejszej weryfikacji:
$ cp -a /tmp/mnt/dir1 /tmp/dir1-check
Kompresuj 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
$
Zauważ, że polecenia działały bez błędów „brak miejsca na urządzeniu”.
dir1
został usunięty, dir1.tar.bz2
istnieje tylko :
$ ls /tmp/mnt
dir1.tar.bz2 lost+found
Rozwiń dir1.tar.bz2
i porównaj z /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
i nieskompresowane dir1.tar.bz2
są identyczne!
Można to uogólnić w skrypcie:
Utwórz plik o nazwie tarrm
(lub dowolną inną nazwę, którą lubisz) z następującymi treściami:
#!/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 "${dir}.tar" -o -f "${dir}.tar.bz2" ]; then
echo "$(basename $0): error: '$dir.tar' or '${dir}.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 ${dir}.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 > "${dir}.tar.bz2"
# return status of last executed command
if [ $? -ne 0 ]; then
echo "$(basename $0): error while creating '${dir}.tar.bz2'" 1>&2
fi
Spraw, by był wykonywalny:
chmod a+x tarrm
Skrypt wykonuje podstawowe sprawdzanie błędów: dir1
musi istnieć, dir1.tar.bz2
i dir1.tar
nie powinno istnieć i ma keep tryb. Obsługuje także nazwy katalogów i plików z osadzonymi spacjami.
Przetestowałem skrypt, ale nie mogę zagwarantować, że jest bezbłędny , więc najpierw użyj go w trybie Keep:
./tarrm dir1 --keep
To wywołanie doda dir1
do dir1.tar.bz2
katalogu, ale go nie usunie.
Jeśli ufasz skryptowi, użyj go w następujący sposób:
./tarrm dir1
Skrypt poinformuje Cię, że dir1
zostanie usunięty w trakcie tarowania go:
Tarring and **deleting** 'dir1'
Na przykład:
$ 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/