WEXITSTATUS 在成功情况下返回 popen() 的无效退出状态

Kir*_*ran 3 c linux bash popen pclose

我正在尝试使用 来获取子进程的存在状态popen()

情况 1:使用 shell 命令调用函数返回错误。这按预期工作。

func("du -sh _invalid_file_");
Run Code Online (Sandbox Code Playgroud)

输出:

du: cannot access '_invalid_file_': No such file or directory
Child exit value: 1
Run Code Online (Sandbox Code Playgroud)

du这里子进程的存在状态与其中运行的退出值相同bash

$ du -sh _invalid_file_
du: cannot access '_invalid_file_': No such file or directory
$ 
$ echo $?
 1
$
Run Code Online (Sandbox Code Playgroud)

情况 2:(错误情况)使用以下 shell 命令调用函数返回成功。在我的代码中,WEXITSTATUS()返回值但返回non-zero相同的命令。bash0

du: cannot access '_invalid_file_': No such file or directory
Child exit value: 1
Run Code Online (Sandbox Code Playgroud)

输出:

Child exit value: 141
Run Code Online (Sandbox Code Playgroud)

请建议解决此问题。粘贴下面的代码。

$ du -sh _invalid_file_
du: cannot access '_invalid_file_': No such file or directory
$ 
$ echo $?
 1
$
Run Code Online (Sandbox Code Playgroud)

pyn*_*exj 5

您在实际从中读取任何数据之前关闭了管道。这将导致子进程接收SIGPIPE(13) 并被终止。

popen()将用于/bin/sh -c运行命令,以便它实际sh -c "du ..."运行。当被(13)du杀死时,会将退出状态设置为 128+13=141,并且由于这是 shell 会话中的最后一个命令,因此 141 将是该命令的最终退出状态,您得到 141。SIGPIPEshdush -c ...

要修复它,您需要先从管道读取数据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;
}
Run Code Online (Sandbox Code Playgroud)

以下内容来自man 7 signal

   Signal     Value     Action   Comment
   ----------------------------------------------------------------------
   ... ...

   SIGPIPE      13       Term    Broken pipe: write to pipe with no
                                 readers; see pipe(7)
   ... ...
Run Code Online (Sandbox Code Playgroud)

这种SIGPIPE行为每天都会发生,尽管并不明显。你可以这样尝试:

   Signal     Value     Action   Comment
   ----------------------------------------------------------------------
   ... ...

   SIGPIPE      13       Term    Broken pipe: write to pipe with no
                                 readers; see pipe(7)
   ... ...
Run Code Online (Sandbox Code Playgroud)

关于 shell 的128+signal行为,以下内容来自man bash (Bash 与 sh 兼容,因此这也适用于 sh。)

当命令因致命信号而终止时 N,bash 使用 的值128+N作为退出状态。