目标是制作一个简单的不引人注目的包装器,将stdin和stdout跟踪到stderr:
>>> def outer2(f):
... def inner2():
... nonlocal val
... val+=1
... print(val)
... return f()
... val = 1
... return inner2
...
>>> function = lambda : 'Function called'
>>>
>>> print(outer2(function)())
2
Function called
测试脚本#!/bin/bash
tee /dev/stderr | ./script.sh | tee /dev/stderr
exit ${PIPESTATUS[1]}
:
script.sh
但是当脚本退出时,它不会终止包装器。可能的解决方案是从管道的第二个命令结束第一个#!/bin/bash
echo asd
sleep 1
exit 4
:
tee
这是很多代码。还有另一种方式吗?
答案 0 :(得分:23)
我认为您正在寻找pipefail选项。从bash手册页:
pipefail
如果设置,管道的返回值是最后一个(最右边)的值 命令以非零状态退出,如果所有命令都为零则为零 管道退出成功。默认情况下禁用此选项。
因此,如果您使用
启动包装器脚本#!/bin/bash
set -e
set -o pipefail
然后,当发生任何错误(set -e
)时,包装器将退出,并将以您希望的方式设置管道的状态。
答案 1 :(得分:6)
这里的主要问题显然是管道。在bash中,当执行以下格式的命令时
command1 | command2
并且command2
死亡或终止,从/dev/stdout
接收输出(command1
)的管道断开。但是,断开的管道不会终止command1
。仅当它尝试写入断开的管道时,这种情况才会发生,并在管道上以sigpipe
退出。在this question中可以看到一个简单的演示。
如果要避免此问题,应使用进程替换而不是管道,并将其重写为:
command2 < <(command1)
对于OP,它将变为:
./script.sh < <(tee /dev/stderr) | tee /dev/stderr
也可以写成:
./script.sh < <(tee /dev/stderr) > >(tee /dev/stderr)