我尝试使用exec来执行bash本身只是为了重定向输出。如果我使用重定向,如
exec >bla.log
ls
exec 1>&2
它按预期工作:ls
输出结束于bla.log
并且在第二个exec
之后恢复正常,主要是因为句柄2仍然绑定到终端。< / p>
现在我想通过管道而不是文件发送输出,一个简单的例子是exec | cat >bla.log
。但是,该命令立即返回。为了弄清楚发生了什么,我做了这个:
exec | bash -c 'echo $$; ls -l /proc/$$/fd /proc/23084/fd'
其中23084是当前正在运行的bash并得到了这个:
24002
/proc/23084/fd:
total 0
lrwx------ 1 harald harald 64 Aug 14 20:17 0 -> /dev/pts/1
lrwx------ 1 harald harald 64 Aug 14 20:17 1 -> /dev/pts/1
lrwx------ 1 harald harald 64 Aug 14 20:17 2 -> /dev/pts/1
lrwx------ 1 harald harald 64 Aug 14 20:17 255 -> /dev/pts/1
/proc/24002/fd:
total 0
lr-x------ 1 harald harald 64 Aug 14 21:56 0 -> pipe:[58814]
lrwx------ 1 harald harald 64 Aug 14 21:56 1 -> /dev/pts/1
lrwx------ 1 harald harald 64 Aug 14 21:56 2 -> /dev/pts/1
如我们所见,子过程24002确实正在监听管道。但它肯定不是父流程23084,它有这个管道打开。
这里有什么想法?
答案 0 :(得分:16)
实现可能以其他方式编写的内容的正确方法
exec | cat >bla.log
是
#!/bin/bash
# ^^^^ - IMPORTANT: not /bin/sh
exec > >(cat >bla.log)
这是因为>()
是process substitution;它被替换为文件名(如果可能的话是/dev/fd/NN
形式,或者用其他临时FIFO替换),当写入时,它将传递给封闭过程的标准输入。 (<()
类似,但在另一个方向:用类似文件的对象的名称替换,当读取时,返回给定进程的标准输出。
因此,exec > >(cat >bla.log)
大致相当于以下内容(在不提供/dev/fd
,/proc/self/fds
或类似内容的操作系统上):
mkfifo "tempfifo.$$" # implicit: FIFO creation
cat >bla.log <"tempfifo.$$" & # ...start the desired process within it...
exec >"tempfifo.$$" # explicit: redirect to the FIFO
rm "tempfifo.$$" # ...and can unlink it immediately.
答案 1 :(得分:5)
当命令包含管道时,每个子命令都在子shell中运行。所以shell首先为管道的每个部分分配一个子shell,然后第一部分的子shell执行exec
而没有参数,它什么也不做并退出。
exec
并且没有命令被视为特殊情况。来自文档:
如果未指定命令,则任何重定向都会在 当前shell,返回状态为0。
答案 2 :(得分:1)
我花了一些时间来弄清楚如何为stdout和stderr获得正确的重定向组合,所以这可能对其他人有用。
以下示例说明了使用tee作为“管道”目标的重定向,同时区分stdout和stderr。
#!/bin/bash
echo "stdout"
echo "stderr" >&2
echo "stdout to out.log" | tee out.log
echo "stderr to err.log" 2>&1 >&2 | tee err.log >&2
exec 2> >(tee -a err.log >&2)
exec > >(tee -a out.log)
echo "exec stdout to out.log"
echo "exec stderr to err.log" >&2
在CLI中运行此命令,并将stdout重定向到/ dev / null,您只能看到stderr消息。在每个日志文件中,您只能看到相关消息。
请注意,exec 2>
行和exec >
行的顺序非常重要。基本上我们首先想要将stderr重定向到错误文件,然后将stdout重定向到日志文件。如果这些行以相反的顺序出现,则结果将不正确。