Bash Shell交换STDERR和STDOUT

你需要交换 STDERR 和 STDOUT,这样就可以将 STDOUT 发送到日志文件,然后用 tee 命令将 STDERR 发送到屏幕和另一个文件。但是,管道仅适用于 STDOUT。

解决方案

在进入管道前用第三个文件描述符交换 STDERR 和 STDOUT:

./myscript 3>&1 1>stdout.logfile 2>&3- | tee -a stderr.logfile

讨论

每次重定向文件描述符时,就会将打开的描述符复制到另一个描述符。这样我们就得到了一种交换描述符的方法,这跟在程序中交换两个值差不多:借助一个临时的第三方位置。将 A 复制到 C,将 B 复制到 A,再将 C 复制到 B,这样就交换了 A 和 B 的值。对于文件描述符,操作如下:

./myscript 3>&1 1>&2 2>&3

将语法 3>&1 读作“使文件描述符 3 指向与标准输出文件描述符 1 相同的值”。这里是将文件描述符 1(STDOUT)复制到文件描述符 3,也就是我们的临时存放位置。然后再将文件描述符 2(STDERR)复制到 STDOUT,最后将文件描述符 3 复制到 STDERR。这样的结果就实现了交换 STDERR 和 STDOUT 文件描述符。

更准确地说,是交换了 STDERR 和 STDOUT 文件描述符的值。

目前一切还算不错。现在我们再略加改动。一旦复制了 STDOUT(复制到文件描述符 3),就可以放心将 STDOUT 重定向到用来捕获脚本或其他程序输出的日志文件。然后,我们再将保存在临时位置(文件描述符 3)的文件描述符复制到 STDERR。添加管道也没有问题,因为管道连接到(最初的)STDOUT。这样就得到了先前看到的解决方案:

./myscript 3>&1 1>stdout.logfile 2>&3- | tee -a stderr.logfile

注意 2>&3- 中结尾的 -。这么做是为了操作完成后关闭文件描述符 3。如此一来,程序就没有额外打开的文件描述符了。我们做到了自己的事情自己整理。

另外还用到了 tee 的 -a 选项,该选项表示追加,而不是替换。

酷客网相关文章:

赞(0)

评论 抢沙发

评论前必须登录!