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 -0w xargsniż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ż tarpodczas przetwarzania pliku czeka na zakończenie archiwizacji przed usunięciem. Ponieważ tarjest pobierany bzip2przez krótki czas, przed jego tarusunię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ę dir1do 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”.
dir1został usunięty, dir1.tar.bz2istnieje tylko :
$ ls /tmp/mnt
dir1.tar.bz2 lost+found
Rozwiń dir1.tar.bz2i 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 dir1i nieskompresowane dir1.tar.bz2są 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: dir1musi istnieć, dir1.tar.bz2i dir1.tarnie 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 dir1do dir1.tar.bz2katalogu, ale go nie usunie.
Jeśli ufasz skryptowi, użyj go w następujący sposób:
./tarrm dir1
Skrypt poinformuje Cię, że dir1zostanie 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/