Bash 获取管道后台进程的退出代码

Bash 获取管道后台进程的退出代码,bash,pipe,background-process,exit-code,Bash,Pipe,Background Process,Exit Code,如何获取someCommand的退出状态 PIPESTATUS不起作用,因为它是后台进程 我发现了这一点,它似乎是有效的,但只有当我使用它正是这样。简单的echoing到屏幕似乎不起作用。我想知道是否可以在不创建临时文件的情况下获取退出代码。在bash中,您可以执行以下操作: someCommand 2>&1 | grep pattern & 例如: echo "${PIPESTATUS[0]} ${PIPESTATUS[1]}" 用于管道式前台进程 如果是脚本,请说t

如何获取
someCommand
的退出状态

PIPESTATUS
不起作用,因为它是后台进程

我发现了这一点,它似乎是有效的,但只有当我使用它正是这样。简单的
echo
ing到屏幕似乎不起作用。我想知道是否可以在不创建临时文件的情况下获取退出代码。

在bash中,您可以执行以下操作:

someCommand 2>&1 | grep pattern &
例如:

echo "${PIPESTATUS[0]} ${PIPESTATUS[1]}"
用于管道式前台进程

如果是脚本,请说testscript.sh,其中包含:

$ ls -l | grep somefile
-rw-rw-r--  1 me me     32 May  4 15:47 somefile
$ echo "${PIPESTATUS[0]} ${PIPESTATUS[1]}"
0 0

$ ls -l 1>/dev/null | grep while
$ echo "${PIPESTATUS[0]} ${PIPESTATUS[1]}"
0 1
$./testscript.sh | grep somestuff
$ echo "${PIPESTATUS[0]} ${PIPESTATUS[1]}"
29 1

用于管道后台进程

方法1:使用pipefail

对于包含以下内容的testscript.sh:

$ ls -l | grep somefile
-rw-rw-r--  1 me me     32 May  4 15:47 somefile
$ echo "${PIPESTATUS[0]} ${PIPESTATUS[1]}"
0 0

$ ls -l 1>/dev/null | grep while
$ echo "${PIPESTATUS[0]} ${PIPESTATUS[1]}"
0 1
$./testscript.sh | grep somestuff
$ echo "${PIPESTATUS[0]} ${PIPESTATUS[1]}"
29 1

您将获得退出状态1的消息,从中可以得出脚本失败的结论。

如果删除了
cat不存在的文件
,您将得到:

$ ./testscript.sh 2>/dev/null | grep Some &
[2] 7684
$ fg 2
bash: fg: job has terminated
[2]-  Exit 1         ./testscript.sh 2> /dev/null | grep --color=auto Some
缺点:pipefail将返回一个非特定于失败命令的“一对所有”退出代码

方法2:获取shell脚本的源代码

[2]-  Done                    ./37257668.sh 2> /dev/null | grep --color=auto Some
最后一键

如果怀疑shell脚本test script中的单个命令失败,可以执行以下操作:

$ . ./testscript.sh 2>/dev/null | grep Some & #mind the dot in the beginning
$ echo "${PIPESTATUS[0]} ${PIPESTATUS[1]}"
29 0

在bash中,您可以执行以下操作:

someCommand 2>&1 | grep pattern &
例如:

echo "${PIPESTATUS[0]} ${PIPESTATUS[1]}"
用于管道式前台进程

如果是脚本,请说testscript.sh,其中包含:

$ ls -l | grep somefile
-rw-rw-r--  1 me me     32 May  4 15:47 somefile
$ echo "${PIPESTATUS[0]} ${PIPESTATUS[1]}"
0 0

$ ls -l 1>/dev/null | grep while
$ echo "${PIPESTATUS[0]} ${PIPESTATUS[1]}"
0 1
$./testscript.sh | grep somestuff
$ echo "${PIPESTATUS[0]} ${PIPESTATUS[1]}"
29 1

用于管道后台进程

方法1:使用pipefail

对于包含以下内容的testscript.sh:

$ ls -l | grep somefile
-rw-rw-r--  1 me me     32 May  4 15:47 somefile
$ echo "${PIPESTATUS[0]} ${PIPESTATUS[1]}"
0 0

$ ls -l 1>/dev/null | grep while
$ echo "${PIPESTATUS[0]} ${PIPESTATUS[1]}"
0 1
$./testscript.sh | grep somestuff
$ echo "${PIPESTATUS[0]} ${PIPESTATUS[1]}"
29 1

您将获得退出状态1的消息,从中可以得出脚本失败的结论。

如果删除了
cat不存在的文件
,您将得到:

$ ./testscript.sh 2>/dev/null | grep Some &
[2] 7684
$ fg 2
bash: fg: job has terminated
[2]-  Exit 1         ./testscript.sh 2> /dev/null | grep --color=auto Some
缺点:pipefail将返回一个非特定于失败命令的“一对所有”退出代码

方法2:获取shell脚本的源代码

[2]-  Done                    ./37257668.sh 2> /dev/null | grep --color=auto Some
最后一键

如果怀疑shell脚本test script中的单个命令失败,可以执行以下操作:

$ . ./testscript.sh 2>/dev/null | grep Some & #mind the dot in the beginning
$ echo "${PIPESTATUS[0]} ${PIPESTATUS[1]}"
29 0

使用临时文件 您可以将保存PIPESTATUS内容的代码放在
{…}
中的临时文件中,并在后台运行它。如果我们对管道中多个命令的退出代码感兴趣,则需要这种方法:

$. ./testscript | grep "Some"

$if [ $ls__return_value -eq 50 ]; then echo "Error in ls"; fi
没有临时文件
等待:等待[n]

{ 
  someCommand 2>&1 | grep -- pattern
  exit ${PIPESTATUS[0]}
} &
wait "$!"
echo $?   # this is the exit code of someCommand
使用临时文件 您可以将保存PIPESTATUS内容的代码放在
{…}
中的临时文件中,并在后台运行它。如果我们对管道中多个命令的退出代码感兴趣,则需要这种方法:

$. ./testscript | grep "Some"

$if [ $ls__return_value -eq 50 ]; then echo "Error in ls"; fi
没有临时文件
等待:等待[n]

{ 
  someCommand 2>&1 | grep -- pattern
  exit ${PIPESTATUS[0]}
} &
wait "$!"
echo $?   # this is the exit code of someCommand


你看过我的问题了吗?我问的是一个有后台进程的案例,我还写到,
PIPESTATUS
在这种情况下不起作用。如何在这里检索退出代码?如果脚本返回
29
,它仍然显示
Done
,而不是
Exit 29
或类似的内容。@NPS:我担心
set-o pipefail
将返回一个
one for all Exit code
,该退出代码不特定于失败的命令,即
Done
表示成功,
1
表示失败。如果将
stderr
重定向到一个文件,您可能会获得有关失败命令的一些信息。在使用我自己的脚本以外的其他脚本(例如
ls
)时,是否可以使用方法1?@NPS:可以。。但是在
ls non|u existing | grep something
之前在终端中设置
set-eo pipefail
,将导致父外壳退出,从而退出终端。您阅读了我的问题吗?我问的是一个有后台进程的案例,我还写到,
PIPESTATUS
在这种情况下不起作用。如何在这里检索退出代码?如果脚本返回
29
,它仍然显示
Done
,而不是
Exit 29
或类似的内容。@NPS:我担心
set-o pipefail
将返回一个
one for all Exit code
,该退出代码不特定于失败的命令,即
Done
表示成功,
1
表示失败。如果将
stderr
重定向到一个文件,您可能会获得有关失败命令的一些信息。在使用我自己的脚本以外的其他脚本(例如
ls
)时,是否可以使用方法1?@NPS:可以。。但是在
ls non|u existing | grep something
之前在终端中设置
set-eo pipefail
,将导致父shell退出,从而退出终端。显示
wait
以何种方式不起作用。@n.m.您自己尝试过吗<代码>ls-lazork | awk'{print$9}'和pid|ls=$!;等待$pid_ls;echo${PIPESTATUS[0]}将
0
打印到屏幕上。如果成功,它将打印
2
,因为
ls
命令失败。显示
wait
以何种方式不起作用。@n.m.您自己试过了吗<代码>ls-lazork | awk'{print$9}'和pid|ls=$!;等待$pid_ls;echo${PIPESTATUS[0]}将
0
打印到屏幕上。如果它工作,它将打印
2
,因为
ls
命令失败。。。管道中有多个命令-我想知道您如何实现这一点。只需在每个命令之后放入
exit${PIPESTATUS[0]}
?另外
wait
manpage说-
wait():成功时,返回终止子进程的进程ID;出现错误时,返回-1
。因此,在
等待“$!”
之后放置
echo$?
对我来说没有多大意义,因为返回的值要么是
进程id
,要么只是
-1
。检查
帮助等待
(将其添加到答案中)<代码>等待pid阻塞,直到pid完成,并给出pid的退出代码。我的回答解决了您知道管道第一部分的退出代码是什么的问题。如果您想知道管道每个部分的出口代码,需要使用temp文件,如所述。Hmm。我懂了