tar到管道,但将-v详细输出与STDERR分开


12

普通的tar命令

tar cvf foo.tar ./foo >foo.out 2>foo.err

具有三个输出IO流

  • 将数据存档到foo.tar
  • 文件名列表到STDOUT(重定向到foo.out)
  • 错误消息到STDERR(重定向到foo.err)

然后,我可以检查foo.err中是否有错误消息,而不必阅读文件名列表。

如果我想对存档数据做一些事情(通过netcat或特殊的压缩程序通过管道传输),则可以使用tar的 -f -选项

tar cvf - ./foo 2>foo.err | squish > foo.tar.S

但是现在我的文件名列表和我的错误消息混在一起了,因为tar的-v输出显然无法转到STDOUT(这是存档数据流的地方),因此tar巧妙地将其写入了STDERR。

使用Korn Shell,有一种方法可以构造一个命令,该命令将存档流传输到另一个命令,但仍然捕获-v输出与任何错误消息。


你熟悉tee吗?这似乎是一个非常有效的用例。
HalosGhost 2015年

Answers:


9

如果您的系统支持/dev/fd/n

tar cvf /dev/fd/3 ./foo 3>&1 > foo.out 2>foo.err | squish > foo.tar.S

使用AT&T的ksh(或bashzsh)实现,您可以使用流程替换来编写:

tar cvf >(squish > foo.tar.S) ./foo > foo.out 2>foo.err

除了这次,shell决定要使用哪个文件描述符而不是3(通常在9以上)外,其他操作完全相同。另一个区别是这次您获得的退出状态tar不是squish。在不支持的系统上/dev/fd/n,某些外壳可能为此功能诉诸命名管道。

如果您的系统不支持,/dev/fd/n或者您的Shell无法使用命名管道进行进程替换,那么您就必须手工处理命名管道


6

您必须为此使用命名管道。

首先在文件夹中创建一个:

mkfifo foo.pipe

然后使用该命令:

tar cvf foo.pipe ./foo >foo.out 2>foo.err & cat foo.pipe >foo.tar

注意:cat双组分,现在也可以gzip也好,都可以从管道中读取:

tar cvf foo.pipe ./foo >foo.out 2>foo.err & gzip -c foo.pipe >foo.tar

说明:

输出被写入到名称管(foo.pipe),其中另一proccess( ,catgzipnetcat从读取。因此,您不会丢失stdout / stderr通道以获取信息。


1
可能值得注意使用命名管道的含义。1)最好是设置一个umask 077(或使用一个私有的temp dir)以防止其他进程对其进行读写(在许多系统上,命名管道,就像默认情况下创建的其他文件一样是世界可读的),2)您需要确保命名管道仅由脚本的每个实例使用(同样,可以使用一个一次性的私有临时目录)3)这意味着您需要在此之后或被中断时进行清理。
斯特凡Chazelas

1
+1-我喜欢这个答案。对于我来说不幸的是,我的(旧)系统上的命名管道有些奇怪,这使它们在我尝试时不可靠。
RedGrittyBrick

1
@StéphaneChazelas-我认为有时候清理起来有时更容易,例如:p="/tmp/pipe$$"; mkfifo "$p"; (read na; cmd[s]...) <>"$p" & (echo;rm "$p"; cmd[s]...) >"$p"
mikeserv 2015年

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.