Tee 重置退出状态始终为0

3

我有一个简短的脚本,像这样:

#!/bin/bash
<some_process> | tee -a /tmp/some.log  &
wait $(pidof <some_process_name>)
echo $?

无论 some_process 的退出状态如何,结果始终为0。
我知道可以使用 PIPESTATUS,在这里,但为什么 tee 会打断 wait?

1
你正在检查最后一个命令的退出状态,这个命令是wait命令。所以如果它成功完成,退出状态将为0。 - Avihoo Mamka
1
@AvihooMamka 不,wait 应该返回指定 pid 的退出状态。 - Yam Marcovic
好的,从其他文档中得到的信息:返回状态: 返回状态是等待的作业的返回状态,或者 0 - 等待了shell作业列表中的所有作业。1 - 给定的ID不是有效的作业或进程ID。 - Avihoo Mamka
我没有说那个。我说的是如果“等待shell作业列表中的所有作业”,返回状态为0。 - Avihoo Mamka
@AvihooMamka 但这里是不是这种情况呢?他在等待特定的进程ID。 - Yam Marcovic
显示剩余8条评论
3个回答

3

好的,这是一些奇怪的事情,文档中没有提到。然而,代码中却有:

int wait_for (pid) { /*...*/
/* If this child is part of a job, then we are really waiting for the
job to finish. Otherwise, we are waiting for the child to finish. [...] */

if (job == NO_JOB)
  job = find_job (pid, 0, NULL);

实际上,它正在等待整个作业完成,正常情况下会产生链中最后一个命令的退出状态。

更糟糕的是,$PIPESTATUS 只能与最后一个 前台 命令一起使用。

但是,您可以在子shell作业中利用 $PIPESTATUS,像这样:

(<some_process> | tee -a /tmp/some.log; exit ${PIPESTATUS[0]}) &
# somewhere down the line:
wait %%<some_process>

1
关键在于同时使用$PIPESTATUSwait -n
查看以下示例:
#!/bin/bash

# start background task
(sleep 5 | false | tee -a /tmp/some.log ; exit ${PIPESTATUS[1]}) &

# foreground code comes here
echo "foo"

# wait for background task to finish
wait -n
echo $?

好的技巧。我觉得你甚至不需要-n,你可以直接给出一个特定的作业编号。 - Yam Marcovic
@YamMarcovic 看起来没有 -nwait 始终会返回 0。我承认 help wait 没有提到这一点。让我调查一下。 - hek2mgl
实际上,这将会阻塞直到第一个任务完成。所以我不确定这是否有用。 - Yam Marcovic
1
嘿,你现在丢失了退出状态,只是返回0/1。当在子shell中时,你可以简单地使用PIPESTATUS[N]来退出(就像我的答案=])。 - Yam Marcovic
1
联合力量,嗯。 :) - Yam Marcovic
显示剩余3条评论

0

你总是得到一个退出状态为0的原因是,返回的退出状态是“管道中最后一个命令”的退出状态,也就是tee。通过使用管道,你消除了对<some_command>正常检测退出状态的影响。

从bash手册中可以看到:

如果启用了pipefail选项,管道的返回状态是最后一个(最右边的)以非零状态退出的命令的值,或者如果所有命令都成功退出,则为零。

所以... 以下可能是你想要的:

#!/usr/bin/env bash

set -o pipefail
<some_command> | tee -a /tmp/some.log  &
wait %1
echo $?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接