我已经阅读了 man on exec
,但仍然不明白我正在研究的脚本中以下两行的后果:
exec >> >(tee -a $logfile)
exec 2>&1
我读了这个答案,但仍存疑虑。
我的理解是,第一行>>
还使输出(追加)到脚本文件中进一步$logfile
右侧的任何内容。>>
第二行将使脚本中的 2 (stderr) 输出重定向到 1 (stdout)。
- 我的理解正确吗?
- 如何撤消上述命令,以便撤消后的行为与执行这两行之前的行为相同?
- 让我们在脚本中进一步说,我们在后台启动一些应用程序,例如
someapp &
。我想在终端中运行此命令 - 与脚本分开且独立 - 其效果与在脚本中运行相同。我应该如何修改someapp &
以使用上面的 s 设置重定向exec
?
答案1
exec >> >(tee -a $logfile)
短缺:
exec 1>> >(tee -a $logfile)
相当于:
exec 1>> /dev/fd/x
其中x
是指向管道写入端的文件描述符。
在此之前,bash
已启动一个子进程,其 fd 0 (stdin) 连接到管道的另一端,同时正忙于执行tee
。
exec 1>> file
,使用 O_APPEND 且不使用 O_TRUNC 打开文件,并将结果 fd 移至 1。
打开/dev/fd/x
,取决于系统,就像执行dup(x)
(大多数)或打开与 fd x 上打开相同的文件(仅限 Linux 和 cygwin)。在这里,当 fd x 在管道上打开时,没有什么区别,并且 O_APPEND 和 O_TRUNCATE 标志是不相关的,因此它与exec > >(...)
.
这有点离题,但tee -a $logfile
不正确,tee -a -- "$logfile"
如果意图是打开路径存储在$logfile
O_APPEND 中的文件,则应该是这样。
因此,在该命令之后,shell 中的 fd 1 将指向一个管道。在管道的另一端,tee
读取即将到来的内容,并将tee
其发送到$logfile
重定向之前 stdout 所指向的内容(如果脚本的输出以某种方式重定向,则可能是终端设备或其他设备) 。
exec 2>&1
使 fd 2 指向与 fd 1 相同的东西,因此是同一个管道。
为了能够做到这一点,你必须保存打开文件描述在进行重定向之前,fds 1 和 2 在单独的 fds 上打开:
exec 3>&1 4>&2 > >(tee -a -- "$logfile") 2>&1
3>&1
so fd 3 现在在哪里dup2(1, 3)
指向与 fd 1 相同的打开文件描述。
并撤消,
exec >&3 2>&4 3>&- 4>&-
someapp
或者以其 stdout 和 stderr 作为原始 stdout 和 stderr运行:
someapp >&3 2>&4 3>&- 4>&- &