我有一个非常大的文件夹,我正在尝试为其创建 tar 存档。问题是我没有足够的额外可用空间来存储整个存档,因此我想一次创建 100-200GB 的存档块,并将它们单独传输到云存储。我需要能够控制何时创建新块,这样我的 HDD 就不会填满,但我发现创建拆分 tarball 的所有命令总是在同一目录中一次性创建所有块。
我找到的最接近的解决方案来自这个问题但所有响应都基于文件数量而不是大小来存档,这对我的用例很重要,因为我的文件大小分布不均匀。
答案1
您可以将tar
, 与以下选项一起使用:
--新卷脚本=命令 --磁带长度=氮
在每个卷结束时,它将调用您的脚本,该脚本将有一些环境变量来了解刚刚处理了哪个卷。查看手册页对于完整列表,但至少该变量TAR_VOLUME
非常有用,以防您必须重命名输出文件,或以某种方式跟踪当前卷:
TAR_VOLUME
正在处理的卷的序号
tar
(如果读取多卷存档则设置)。
如果脚本返回0,tar
将继续,否则将停止。
例如,这将创建最大大小为 20 M 的每个卷,并在每次达到限制时调用您的脚本:
tar cvf /tmp/volume.tar /path/to/files/ --new-volume-script=/path/to/myscript.sh --tape-length=20M
该脚本可以很简单echo "Next volume";read
,或者您甚至可以从中进行传输(重命名卷,因为一旦退出/tmp/volume.tar
就会被覆盖)。
另一方面,请务必使用 flag --multi-volume
。如果不这样做,tar 将停止并显示错误(我将其保留,以防有人搜索错误):
tar: Unexpected EOF in archive
tar: Error is not recoverable: exiting now
tar xvf /path/to/transferred.volume --multi-volume
Prepare volume #2 for /path/to/transferred.volume and hit return:
tar
将提示您输入新卷。一旦按下Enter,/path/to/transferred.volume
将再次打开,依此类推。
答案2
跟进爱德华多·特拉帕尼很好的答案,下面是在上找到的脚本的稍微修改版本GNU 页面等待每个卷的用户输入,如果找不到卷则重试:
为了完整起见,这是用于创建存档的命令:
tar cvf /tmp/volume.tar /path/to/files/ --new-volume-script=./myscript.sh --tape-length=1000M
这是我用来提取分割存档的命令:
tar xvf /tmp/volume.tar --multi-volume --new-volume-script=./myscript.sh
myscript.sh:
#!/bin/bash
# For this script it's advisable to use a shell, such as Bash,
# that supports a TAR_FD value greater than 9.
echo "Press enter to continue to next volume"
read
echo Preparing volume $TAR_VOLUME of $TAR_ARCHIVE.
name=`expr $TAR_ARCHIVE : '\(.*\)-.*'`
case $TAR_SUBCOMMAND in
-c) ;;
-d|-x|-t) test -r ${name:-$TAR_ARCHIVE}-$TAR_VOLUME || echo "Failed to find volume"
;;
*) exit 1
esac
echo ${name:-$TAR_ARCHIVE}-$TAR_VOLUME >&$TAR_FD
编辑:这仅适用于 GNU Tar,可以通过以下方式安装在 macOS(带 Homebrew)上:
brew install gnu-tar
要将其用作默认 tar,您需要将其添加到您的路径中,如下所示:
export PATH="$(brew --prefix)/opt/python/libexec/bin:$PATH"
答案3
我尝试使用乔什·哈里森的回答这对我来说不起作用。
我没有真正的 SSH 访问服务器,因为它是托管主机。我在用着https://github.com/flozz/p0wny-shell拥有像贝壳一样的东西。
问题是,p0wny-shell 不提供标准输入流,因此该read
命令没有停止脚本,并且各个部分仍然被一个接一个地创建而没有暂停。
我做了修改,让它自动将部件一一移动到新服务器上:
- 创建零件
- 上传该部分并删除它
- 重复直到创建所有零件
- 手动上传最后一部分
- 使用原始 myscript.sh 在远程服务器上将其解压(没有
read
在各部分之间停止)
#!/bin/bash
# For this script it's advisable to use a shell, such as Bash,
# that supports a TAR_FD value greater than 9.
if [[ $TAR_SUBCOMMAND != '-c' ]]; then
echo 'This script can only be used to compress with -c option'
exit 1;
fi
# $TAR_ARCHIVE per run:
# 1. archive.tar
# 2. archive.tar-2
# 3. archive.tar-3
# ...
# $TAR_ARCHIVE_NAME per run
# 1. <empty>
# 2. archive.tar
# 3. archive.tar
# ...
TAR_ARCHIVE_NAME=`expr $TAR_ARCHIVE : '\(.*\)-.*'`
# $TAR_ARCHIVE_BASE_NAME per run
# 1. archive.tar
# 2. archive.tar
# 3. archive.tar
# ...
TAR_ARCHIVE_BASE_NAME=${TAR_ARCHIVE_NAME:-$TAR_ARCHIVE}
if (( $TAR_VOLUME == 2 )); then
# On the first run $TAR_VOLUME will be '2', we want to use the base name
TAR_ARCHIVE_PREV_PART=$TAR_ARCHIVE_BASE_NAME
elif (( $TAR_VOLUME >= 3 )); then
# On the next runs $TAR_VOLUME we want to build the name with the previous $TAR_VOLUME
TAR_PREV_VOLUME=$(($TAR_VOLUME-1))
TAR_ARCHIVE_PREV_PART=$TAR_ARCHIVE_BASE_NAME-$TAR_PREV_VOLUME
fi
echo "Copying $TAR_ARCHIVE_PREV_PART..."
# SSH key was previously created with `ssh-keygen -f ./id_rsa_user` and public key was added to remote
scp \
-o StrictHostKeyChecking=no \
-i '/usr/www/users/user/.ssh/id_rsa_user' \
$TAR_ARCHIVE_PREV_PART \
[email protected]:/home/user/path/to/target/
echo "Removing $TAR_ARCHIVE_PREV_PART..."
rm $TAR_ARCHIVE_PREV_PART
echo Preparing volume $TAR_VOLUME of $TAR_ARCHIVE_BASE_NAME.
echo $TAR_ARCHIVE_BASE_NAME-$TAR_VOLUME >&$TAR_FD