我正在研究答案这里编写备份脚本。我的脚本大致如下
backup_files="/etc /home"
excludes="--exclude-vcs --exclude-ignore-recursive=.tarignore"
#(Skip irrelevant details)
total_size= du -csb $backup_files |awk '{print $1}'|tail -n 1
tar cf - $excludes $backup_files -P | pv -s $total_size | gzip > "$target_file"
只是,计算结果total_size
高估了时间量。我一直在修改脚本以缩小估计值,但遇到了一些问题。例如,我尝试过
all_files=$(tar cvf /dev/null $excludes $backup_files -P |grep -v -e /$)
total_size=$(du -csb $all_files)
这会导致参数过多(大约一百万个文件)的问题。使用 for 循环迭代此文件会导致文件名问题。除其他问题外,空格会中断循环,一些奇怪的 Unicode 文件名会中断。此外,我尝试对循环进行计时,结果需要几个小时。
通过评论中的一些指点和一个现已删除的答案,我已经
run_tar () {
printf '%s\n' "$excludes" "$backup_files" | tar -cSPf - --files-from -
}
list_files () {
printf '%s\n' "$excludes" "$backup_files" | tar -cvPf /dev/null --files-from - | grep -v -e /$
}
compute_size(){
list_files | while read -r f;
do
echo -ne "$f\0"
done | du -csb --files0-from - |awk '{print $1}'|tail -n 1
}
这解决了 for 循环的开销和空格问题。目前,处理一百万个左右的文件大约需要一两分钟。
我仍然遇到 Unicode 错误。文件名呈现为例如Yle P\344\344uutiset.xml
。将错误转发到/dev/null
隐藏了问题,而且无论如何这只是少数文件。ls
其中一个行为不当的目录的 A 显示有一个名为的文件'Yle P'$'\344\344''uutiset.xml'
。我认为这个实例是文件名损坏的情况,但问题仍然是这些仍然是有效的文件名。就此而言,换行符也是有效的文件名分隔符。
我该如何将缺失的几个文件包含在总数中?
答案1
您问如何预先计算究竟需要处理多少字节tar
,以便您可以知道pv
将通过它的数据总量,以便它计算准确的进度统计数据。
这可以通过指示 tar 写入 来完成/dev/null
,因此实际上没有读取或写入任何数据,然后使用--totals
打印总字节数的选项,例如:
tar --create --file /dev/null --totals --exclude=PATTERN FILE...
输出内容如下:
Total bytes written: 513318768640 (479GiB, 464GiB/s)
当我们跑步时
tar --create --exclude=PATTERN FILE... | wc -c
(哪个做读取所有数据)我们可以看到通过管道传递的字节数确实和之前报告的完全一样。
现在,为了将数字本身存储在变量中,我们可以通过管道将输出传输到awk
,结果总数被 tar 写入标准错误 - 而不是标准输入 - 因此我们需要使用|&
(或2>&1 |
) 而不是|
:
total_size=$(tar -cf /dev/null --totals --exclude=PATTERN FILE... |& awk '{print $4}')
然后你的实际归档将通过以下方式完成:
tar --create --exclude=PATTERN FILE... | pv -s "$total_size" | gzip > "$target_file"
它将向您显示准确的进度计。