无法使用 set -eo pipefail 在管道中成功调用任何外部 shell 脚本
Can't successfully call any external shell script in pipe with set -eo pipefail
假设以下test-pipefail.sh批次:
#!/usr/bin/env bash
set -eo pipefail
./echoer.sh | head -n1 >/dev/null
echo "Might work with pipefail"
for i in {1..100} ; do
./echoer.sh | head -n1 >/dev/null
done
echo "Stable work with pipefail"
含echoer.sh内容:
#!/usr/bin/env bash
echo 'head (GNU coreutils) 8.30'
echo 'GNU bash, version 5.0.16(1)-release (x86_64-pc-linux-gnu)'
exit 0
./test-pipefail.sh的预期结果:
Might work with pipefail
Stable work with pipefail
实际行为:
Might work with pipefail
或(随机)没有输出。
如果我使用任何二进制实用程序而不是 echoer.sh,pipe 中的 Writer 程序永远不会失败,但它总是不起作用(导致 pipefail 脚本到exit) 如果 writer 是 shell 脚本(例如,来自 glibc 二进制包的 ldd)。
将 test-pipefail.sh 中的执行 (./echoer.sh) 替换为采购 (.echoer.sh) 线索
成功执行的可能性增加,即有时我得到
Stable work with pipefail
在测试-pipefail.sh输出。
head always returns 在这种管道中取得成功。
删除 echoer.sh 中的第二个 echo 会导致在单独的 shell.
中成功执行采购和执行
我认为结果取决于 writer 完成的速度。如果它完成得非常快,那么它就没有机会与 SIGPIPE
.
一起发送
例如:
[STEP 119] # hexdump -n100 /dev/urandom | head -n1; echo '$?'=$?
0000000 eea2 36e7 24d8 15de 620c e258 f9d8 f138
$?=0
[STEP 120] # hexdump -n1000 /dev/urandom | head -n1; echo '$?'=$?
0000000 cf81 dd51 1594 88b2 c9c1 6c8a bbbd c80f
$?=0
[STEP 121] # hexdump -n1000 /dev/urandom | head -n1; echo '$?'=$?
0000000 ef2d b2d3 1024 af9f ee1e a5e6 5528 699e
$?=0
[STEP 122] # hexdump -n2000 /dev/urandom | head -n1; echo '$?'=$?
0000000 d9f7 6a0d 633b c1f7 8928 cef8 3ea9 6f5a
$?=141
[STEP 123] # hexdump -n2000 /dev/urandom | head -n1; echo '$?'=$?
0000000 c044 dbb0 c227 1836 9fb5 f03b b2d1 0605
$?=141
[STEP 124] #
让我们把问题归结为最基本的问题。考虑:
$ (set -o pipefail; cat /dev/zero | head -c10; declare -p PIPESTATUS)
declare -a PIPESTATUS=([0]="141" [1]="0")
发生的事情是,当 head
填满时,它完成,关闭管道。前面的命令,在本例中为 cat
,获取 SIGPIPE (13) 信号。因此,它将其退出代码设置为 128+13=141 以指示失败。
所以,问题是当第二个进程 head
完成时,第一个进程是否仍然 运行。有时,您的 echoer.sh
比 head
快,有时又慢。
由于我们同时处理两个进程,所以时间总是可变的。
采购与执行
Replacing execution (./echoer.sh
) in test-pipefail.sh with sourcing (. echoer.sh
) leads to increased probability of successful execution
采购消除了初始化新 shell 的需要,这可能会导致执行速度更快,因此更有可能在 head
.
之前完成
二进制程序
Writer program in pipe never fails if I'm using any binary utility
instead of echoer.sh
我上面的 cat
示例显示了相反的情况。这是因为 cat /dev/zero
程序将 永远不会 完成,从而确保它最终会收到 SIGPIPE。
假设以下test-pipefail.sh批次:
#!/usr/bin/env bash
set -eo pipefail
./echoer.sh | head -n1 >/dev/null
echo "Might work with pipefail"
for i in {1..100} ; do
./echoer.sh | head -n1 >/dev/null
done
echo "Stable work with pipefail"
含echoer.sh内容:
#!/usr/bin/env bash
echo 'head (GNU coreutils) 8.30'
echo 'GNU bash, version 5.0.16(1)-release (x86_64-pc-linux-gnu)'
exit 0
./test-pipefail.sh的预期结果:
Might work with pipefail
Stable work with pipefail
实际行为:
Might work with pipefail
或(随机)没有输出。
如果我使用任何二进制实用程序而不是 echoer.sh,pipe 中的 Writer 程序永远不会失败,但它总是不起作用(导致 pipefail 脚本到exit) 如果 writer 是 shell 脚本(例如,来自 glibc 二进制包的 ldd)。 将 test-pipefail.sh 中的执行 (./echoer.sh) 替换为采购 (.echoer.sh) 线索 成功执行的可能性增加,即有时我得到
Stable work with pipefail
在测试-pipefail.sh输出。
head always returns 在这种管道中取得成功。 删除 echoer.sh 中的第二个 echo 会导致在单独的 shell.
中成功执行采购和执行我认为结果取决于 writer 完成的速度。如果它完成得非常快,那么它就没有机会与 SIGPIPE
.
例如:
[STEP 119] # hexdump -n100 /dev/urandom | head -n1; echo '$?'=$?
0000000 eea2 36e7 24d8 15de 620c e258 f9d8 f138
$?=0
[STEP 120] # hexdump -n1000 /dev/urandom | head -n1; echo '$?'=$?
0000000 cf81 dd51 1594 88b2 c9c1 6c8a bbbd c80f
$?=0
[STEP 121] # hexdump -n1000 /dev/urandom | head -n1; echo '$?'=$?
0000000 ef2d b2d3 1024 af9f ee1e a5e6 5528 699e
$?=0
[STEP 122] # hexdump -n2000 /dev/urandom | head -n1; echo '$?'=$?
0000000 d9f7 6a0d 633b c1f7 8928 cef8 3ea9 6f5a
$?=141
[STEP 123] # hexdump -n2000 /dev/urandom | head -n1; echo '$?'=$?
0000000 c044 dbb0 c227 1836 9fb5 f03b b2d1 0605
$?=141
[STEP 124] #
让我们把问题归结为最基本的问题。考虑:
$ (set -o pipefail; cat /dev/zero | head -c10; declare -p PIPESTATUS)
declare -a PIPESTATUS=([0]="141" [1]="0")
发生的事情是,当 head
填满时,它完成,关闭管道。前面的命令,在本例中为 cat
,获取 SIGPIPE (13) 信号。因此,它将其退出代码设置为 128+13=141 以指示失败。
所以,问题是当第二个进程 head
完成时,第一个进程是否仍然 运行。有时,您的 echoer.sh
比 head
快,有时又慢。
由于我们同时处理两个进程,所以时间总是可变的。
采购与执行
Replacing execution (
./echoer.sh
) in test-pipefail.sh with sourcing (. echoer.sh
) leads to increased probability of successful execution
采购消除了初始化新 shell 的需要,这可能会导致执行速度更快,因此更有可能在 head
.
二进制程序
Writer program in pipe never fails if I'm using any binary utility instead of
echoer.sh
我上面的 cat
示例显示了相反的情况。这是因为 cat /dev/zero
程序将 永远不会 完成,从而确保它最终会收到 SIGPIPE。