有没有办法将名为 dir1 的目录转换为 dir1.tar.bz2 而不保留原始文件?我需要节省空间并想压缩一些大文件,但没有足够的空间来保存压缩副本和原始文件。有没有办法将现有文件直接转换为存档?
答案1
tar
无法做到这一点,但您可以通过以下方式实现您想要的:
find dir1 -depth -print0 | xargs -0 tar --create --no-recursion --remove-file --file - | bzip2 > dir1.tar.bz2
在哪里:
find dir1 -depth -print0
列出 中的所有文件和目录
dir1
,在目录本身之前列出目录内容(-depth
)。使用-print0
(下面和-0
)xargs
是支持带有嵌入空格的目录和文件名。xargs -0 tar --create --no-recursion --remove-file --file -
创建一个 tar 存档并将每个文件或目录添加到其中。使用选项 ,将 tar 存档发送到标准输出
--file -
。bzip2 > dir1.tar.bz2
将 tar 档案从标准输入压缩到名为 的文件中
dir1.tar.bz2
。
所需的可用磁盘空间量是dir1
因为tar
处理文件时,会等到归档完成后再删除。由于tar
被管道传输到bzip2
,所以在删除之前会短暂地传输tar
,因此每个文件都位于两个位置:文件系统中未压缩的文件和 内部压缩的文件dir1.tar.bz2
。
我很好奇磁盘空间是如何使用的,所以我在我的 Ubuntu VM 上做了这个实验:
创建一个 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
用 900 个 1 兆字节文件填充文件系统:
$ 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
文件系统现在已满 98%。
复制一份
dir1
以供日后核实:$ cp -a /tmp/mnt/dir1 /tmp/dir1-check
压缩
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 $
请注意,命令运行时没有出现任何“设备上没有剩余空间”错误。
dir1
已被删除,仅dir1.tar.bz2
存在:$ ls /tmp/mnt dir1.tar.bz2 lost+found
展开
dir1.tar.bz2
并比较为/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 $
副本
dir1
和未压缩dir1.tar.bz2
的完全相同!
这可以在脚本中概括:
tarrm
创建一个名为(或您喜欢的任何其他名称) 的文件,其内容如下:#!/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
使其可执行:
chmod a+x tarrm
该脚本进行了一些基本的错误检查:dir1
必须存在、dir1.tar.bz2
不dir1.tar
应该存在以及有一个保持模式。它还支持带有嵌入空格的目录名和文件名。
我已经测试过该脚本,但不能保证它完美无缺,因此首先在保持模式下使用它:
./tarrm dir1 --keep
此调用将添加dir1
但dir1.tar.bz2
不会删除目录。
当您信任该脚本时,请按如下方式使用它:
./tarrm dir1
该脚本将通知您dir1
在 tarring 过程中将被删除:
Tarring and **deleting** 'dir1'
例如:
$ 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/