我一直在寻找一种使用Bash间接将所有输出(1(STDOUT),2(STDERR),3等)重新路由到命名管道的方法。这是我为测试该理论而编写的脚本:
#!/bin/bash
pipe1="/tmp/pipe1"
pipe2="/tmp/pipe2"
pipe3="/tmp/pipe3"
mkfifo "${pipe1}"
mkfifo "${pipe2}"
mkfifo "${pipe3}"
trap "rm -rf ${pipe1} ${pipe2} ${pipe3}" EXIT
printer() {
echo "OUT" >&1
echo "ERR" >&2
echo "WRN" >&3
}
# Usage: mux
mux() {
cat "${pipe1}"
cat "${pipe2}"
cat "${pipe3}"
}
printer 1>"${pipe1}" 2>"${pipe2}" 3>"${pipe3}"
mux
此代码似乎还不错,但是终端无限期地挂起,直到终止为止。据我了解,管道就像文件一样,因为它们具有一个索引节点,但是它们不是写入磁盘,而是直接写入内存。
话虽如此,它应该像其他任何文件一样可访问。我知道脚本挂在调用打印机函数的行上。我还测试了子外壳程序和更高级的重定向(即,重定向到STDOUT以处理其他每个管道)的几种组合。也许我在命名管道中缺少终止符(因此该终止符已被锁定,无法通过mux函数访问)。如果是这样,那如何实现?
编辑 经过更多测试后,看来该问题仅在尝试使用多个管道进行重定向时发生。例如:
#!/bin/bash
pipe1="/tmp/pipe1"
mkfifo "${pipe1}"
trap "rm -rf ${pipe1}" EXIT
(exec >"${pipe1}"; echo "Test") &
cat < "${pipe1}"
将按预期工作。但是,例如添加STDOUT会破坏它,迫使其挂起:
#!/bin/bash
pipe1="/tmp/pipe1"
mkfifo "${pipe1}"
trap "rm -rf ${pipe1}" EXIT
(exec >"${pipe1}" 2>"${pipe2}"; echo "Test"; echo "Test2" >&2) &
cat < "${pipe1}"
cat < "${pipe2}"
更具体地说,一旦执行exec >"${pipe1}" 2>"${pipe2}
语句,代码就会挂起。我想在某些地方添加更多子壳会有所帮助,但这可能会变得凌乱/笨拙。但是,我确实了解到,命名管道是用于在shell之间桥接数据的(因此,添加了子shell和后台操作符&
)。
答案 0 :(得分:1)
如果要在关闭文件描述符后能够读取内容,则只需使用文件即可。使用管道的想法是,在写入命令之前,先要运行读取命令。
在这种设置下:
cmd1 | cmd2 | cmd3
首先运行 cmd3
,然后运行cmd2
,然后运行cmd1
。因此,如果要使用管道进行设置,则需要打开每个fifo进行并行读取,然后调用printer
:
printer() {
echo "OUT" >&1
echo "ERR" >&2
echo "WRN" >&3
}
# Usage: mux
mux() {
cat "${pipe1}" &
cat "${pipe2}" &
cat "${pipe3}"
}
mux &
printer 1>${pipe1} 2>"${pipe2}" 3>"${pipe3}"
外壳将在此被阻止时阻塞:
(exec >"${pipe1}" 2>"${pipe2}"; echo "Test"; echo "Test2" >&2) &
cat < "${pipe1}"
cat < "${pipe2}"
在cat < "$pipe1"
上,因为您需要从两个管道中读取内容才能使exec继续:
(exec >"${pipe1}" 2>"${pipe2}"; echo "Test"; echo "Test2" >&2) &
cat < "${pipe1}" &
cat < "${pipe2}"
如果要从命令缓冲输出,即。写入命令或退出命令后,读取命令的输出,仅使用该命令的文件,它们实际上称为日志。
作为一种解决方法,您可以使用bash管道内部缓冲来缓冲您的消息:
printer() {
echo "OUT" >&3
echo "ERR" >&4
echo "WRN" >&5
}
# Usage: mux
mux() {
timeout 1 cat "${pipe1}"
timeout 1 cat "${pipe2}"
timeout 1 cat "${pipe3}"
}
printer 3> >(cat >$pipe1) 4> >(cat >$pipe2) 5> >(cat >$pipe3)
mux
这里发生的是,即使打印机功能存在,管道也始终处于打开状态以进行写入,并且一直保持打开状态,直到运行进程替换为止。您可以通过exec 5>&-
手动关闭它们,这会将EOF写入管道,从而使cat $pipe3
正常返回。如果函数未关闭文件描述符,cat "$pipe1"
将永远不会退出,这就是使用超时函数的原因,这样我们就可以在不阻塞管道的情况下清空管道。