我需要使用像xz这样的压缩器来压缩巨大的tar档案。
我完全了解以前的问题 Create a tar.xz in one command 和 Utilizing multi core for tar+gzip/bzip compression/decompression
从他们那里,我发现这个命令行主要起作用:
tar -cvf - paths_to_archive | xz -1 -T0 -v > OUTPUT_FILE.tar.xz
我使用管道解决方案,因为我绝对必须能够将选项传递给xz。特别是,xz非常占用CPU,所以我必须使用-T0来使用所有可用的内核。这就是为什么我没有使用其他可能性,比如tar的--use-compress-program或-J选项。
不幸的是,我真的想要将所有tar和xz的日志输出(即非归档输出)捕获到日志文件中。在上面的示例中,log outout始终由-v
个选项生成。
使用上面的命令行,该日志输出现在打印在我的终端上。
所以,问题是当你使用管道来连接tar和xz时,你不能用
这样的命令行结束命令行>Log_File 2>&1
因为早先的
> OUTPUT_FILE.tar.xz
有解决方案吗?
我尝试在这样的子shell中包装
(tar -cvf - paths_to_archive | xz -1 -T0 -v > OUTPUT_FILE.tar.xz) >Log_File 2>&1
但这没效果。
答案 0 :(得分:1)
tar
的正常标准输出是tarball,xz
的正常标准输出是压缩文件。这些都不是您想要捕获的日志。 除输出文件本身以外的所有日志记录都是专门为stderr写入的。
因此,您只需要重定向stderr,并且一定不能重定向标准输出,除非您希望输出文件与日志记录混在一起。
{ tar -cvf - paths_to_archive | xz -1 -T0 -v > OUTPUT_FILE.tar.xz; } 2>Log_File
顺便说一下 - 如果您对xz -v
输出到TTY时打印更多内容的原因感到好奇,答案是in this line of message.c
:progress_automatic
标记(告诉xz设置一个计时器来触发一个SIGALRM
- 它被视为表示应该打印状态 - 每秒一次)仅在isatty(STDERR_FILENO)
为真时设置。因此,在将stderr重定向到文件后,xz
根本不再打印此输出;问题不在于它没有被正确地重定向,而是不再存在。
但是,如果你真的如此倾向,你可以每秒从你自己的代码发送SIGALRM
到xz
:
{
xz -1 -T0 -v > OUTPUT_FILE.tar.xz < <(tar -cvf - paths_to_archive) & xz_pid=$!
while sleep 1; do
kill -ALRM "$xz_pid" || break
done
wait "$xz_pid"
} 2>Log_File
(避免将xz
执行到最近的秒所需的时间四舍五入的代码是可能的,但留给读者的练习。)
答案 1 :(得分:0)
首先-cvf -
可以替换为cv
。
但是tar cvf -
的正常stdout输出是通过管道传输到xz
的tar文件。不确定我是否完全理解,也许这个:
tar cv paths | xz -1 -T0 > OUTPUT.tar.xz 2> LOG.stderr
或
tar cv paths 2> LOG.stderr | xz -1 -T0 > OUTPUT.tar.xz
或
tar cv paths 2> LOG.tar.stderr | xz -1 -T0 > OUTPUT.tar.xz 2> LOG.xz.stderr
不确定-T0
是否已实施,您使用的是哪个版本的xz? (可能https://github.com/vasi/pixz值得仔细研究)pv
程序在某些系统上与sudo apt-get install pv
一起安装,在显示管道进度方面比xz -v
更好。它将以ETA的百分比形式告诉您进度:
size=$(du -bc path1 path2 | tail -1 | awk '{print$1}')
tar c paths 2> LOG.stderr | pv -s$size | xz -1 -T0 > OUTPUT.tar.xz