popen+pclose 执行 shell 命令

来源:互联网 发布:酷酷跑软件 编辑:程序博客网 时间:2024/06/04 18:23

在《system() 执行 shell 命令》中,我们介绍了 system 执行 shell 命令的方法,system 返回值比较混乱,难以理解,而且 popen 在处理子进程标准输出上会很方便。

注意:管道只能处理标准输出,不能处理标准错误输出。


popen 和 pclose 的实现与 system 类似,多了一步创建管道的操作。

popen 成功返回 FILE 句柄,失败返回 NULL, 失败的原因可能为 fork 或 pipe 失败,也可能为分配内存失败;

pclose 失败返回 -1, 成功则返回 exit status, 同 system 类似,需要用 WIFEXITED, WEXITSTATUS 等获取命令返回值。


此外,同 system 类似, pclose 会等待进程退出,如果等不到进程退出(例如已经被 wait 回收),则 error 设置为 ECHILD.

注意:

1. pclose 仅仅是为了回收子进程,避免僵尸进程的产生;

2. 和 system 一样,SIGCHLD  依然会影响 popen,见示例程序。

#include <stdio.h>#include <errno.h>#include <stdlib.h>#include <string.h>#include <signal.h>typedef void (*sighandler_t)(int);int main(int argc, char* argv[]){    char cmd[1024];    char line[1024];    FILE* pipe;    int rv;    if (argc != 2)    {        printf("Usage: %s <path>\n", argv[0]);        return -1;    }    // pclose fail: No child processes    signal(SIGCHLD, SIG_IGN);            snprintf(cmd, sizeof(cmd), "ls -l %s 2>/dev/null", argv[1]);    //sighandler_t old_sighandler = signal(SIGCHLD, SIG_DFL);    pipe = popen(cmd, "r");    if(NULL == pipe)    {        printf("popen() failed: %s\n", cmd);        return -1;    }        while(fgets(line, sizeof(line),pipe) != NULL)    {        printf("%s", line);    }    rv = pclose(pipe);    //signal(SIGCHLD, old_sighandler);        if (-1 == rv)    {        printf("pclose() failed: %s\n", strerror(errno));        return -1;    }        if (WIFEXITED(rv))    {        printf("subprocess exited, exit code: %d\n", WEXITSTATUS(rv));        if (0 == WEXITSTATUS(rv))        {            // if command returning 0 means succeed            printf("command succeed\n");        }        else        {            if(127 == WEXITSTATUS(rv))            {                printf("command not found\n");                return WEXITSTATUS(rv);            }            else            {                printf("command failed: %s\n", strerror(WEXITSTATUS(rv)));                return WEXITSTATUS(rv);            }        }    }    else    {        printf("subprocess exit failed\n");        return -1;    }     return 0;}

说明:

1. 将 SIGCHLD 忽略之后,pclose 不能回收子进程退出信息,errno 为 ECHILD, 错误信息为 "No child processes";

2. 由于管道不能捕获 stderr, 因此命令将 stderr 重定向至 /dev/null.


0 0
原创粉丝点击