一个普通的 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
与任何错误消息分开的输出。
答案1
如果您的系统支持/dev/fd/n
:
tar cvf /dev/fd/3 ./foo 3>&1 > foo.out 2>foo.err | squish > foo.tar.S
对于ksh
(orbash
或zsh
) 的 AT&T 实现,您可以使用流程替代:
tar cvf >(squish > foo.tar.S) ./foo > foo.out 2>foo.err
这实际上是在做同样的事情,只不过这一次,shell 决定使用哪个文件描述符3
(通常在 9 以上)。另一个区别是,这一次,您获得的退出状态是 ,tar
而不是squish
。在不支持 的系统上/dev/fd/n
,某些 shell 可能会借助命名管道来实现该功能。
如果你的系统不支持,/dev/fd/n
或者你的 shell 不能使用命名管道进行进程替换,那么你就必须手动处理命名管道。
答案2
为此,您必须使用命名管道。
首先在文件夹中创建一个:
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
),另一个进程 ( cat
, gzip
, netcat
) 从中读取。因此,您不会丢失 stdout/stderr 信息通道。
答案3
GNU tar 的--index-file
选项效果很好:
tar cvf - ./foo 2>foo.err --index-file=foo.out | squish > foo.tar.S