我正在尝试使用 popen()
获取子进程的存在状态。
案例一:调用函数时shell命令返回错误。这按预期工作。
func("du -sh _invalid_file_");
输出:
du: cannot access '_invalid_file_': No such file or directory
Child exit value: 1
这里的子存在状态与 bash
中运行的 du
的退出值相同。
$ du -sh _invalid_file_
du: cannot access '_invalid_file_': No such file or directory
$
$ echo $?
1
$
案例 2:(错误案例) 使用以下 shell 命令调用函数返回成功。
在我的代码中,WEXITSTATUS()
返回 非零
值,但 bash
中的相同命令返回 0
。
func("du -sh");
输出:
Child exit value: 141
请建议解决此问题。粘贴下面的代码。
int func(char *cmd)
{
FILE *pfp = NULL;
int retval, status;
pfp = popen(cmd, "r");
if (pfp == NULL) {
perror("popen failed");
exit(1);
}
status = pclose(pfp);
if (status < 0) {
perror("pclose error");
} else {
if (WIFEXITED(status)) {
retval = WEXITSTATUS(status);
printf("Child exit value: %d\n", retval);
}
}
return 0;
}
最佳答案
您在实际从中读取任何数据之前关闭了管道。这将导致子进程接收到 SIGPIPE
(13) 并被杀死。
popen()
会使用 /bin/sh -c
来运行命令所以它实际上是 sh -c "du ..."
运行。当 du
被 SIGPIPE
(13) 杀死时,sh
会将退出状态设置为 128+13=141,因为 du
是 shell session 中的最后一个命令,因此 141 将是 sh -c ...
命令的最终退出状态,您得到 141。
要修复它,您需要在 pclose()
之前从管道中读取数据。
int func(char *cmd)
{
FILE *pfp = NULL;
char buf[1024];
int retval, status;
pfp = popen(cmd, "r");
if (pfp == NULL) {
perror("popen failed");
exit(1);
}
/* read from the pipe or close() may cause the process to receive SIGPIPE */
while (fgets(buf, sizeof buf, pfp) ) {
printf("%s", buf);
}
status = pclose(pfp);
if (status < 0) {
perror("pclose error");
} else {
if (WIFEXITED(status)) {
retval = WEXITSTATUS(status);
printf("Child exit value: %d\n", retval);
}
}
return 0;
}
以下内容来自man 7 signal
:
Signal Value Action Comment
----------------------------------------------------------------------
... ...
SIGPIPE 13 Term Broken pipe: write to pipe with no
readers; see pipe(7)
... ...
这种SIGPIPE
行为每天都会发生,尽管并不明显。你可以这样尝试:
$ od /dev/urandom | head -n1
0000000 067255 052464 166240 113163 122024 054232 015444 110641
$ declare -p PIPESTATUS # see PIPESTATUS in `man bash'
declare -a PIPESTATUS=([0]="141" [1]="0")
$
$ { od /dev/urandom; echo EXIT=$? >&2; } | head -n1
0000000 020553 063350 025451 116300 006505 151644 122151 175763
EXIT=141
关于 shell 的 128+signal
行为,以下内容来自 man bash
(Bash 与 sh 兼容,因此这也适用于 sh。)支持>:
When a command terminates on a fatal signal
N
, bash uses the value of128+N
as the exit status.
关于c - WEXITSTATUS 在成功案例中返回 popen() 的无效退出状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73061212/