0%

C语言和python获取命令行的返回内容

C语言获取命令行的返回内容

  • 参考链接
  • 示例程序
    #include <stdio.h>
    #include <string.h>
    #include <errno.h>

    int main(void)
    {
    char* szCmd = "ls -l";
    FILE* pResultStr = NULL;
    char szBuf[1024] = {0};

    /* 创建子进程,执行shell命令 */
    pResultStr = popen(szCmd, "r");
    if (NULL == pResultStr)
    {
    printf("popen faild. (%d, %s)\n",errno, strerror(errno));
    return -1;
    }

    /* 获取返回结果 */
    fread(szBuf, 1, sizeof(szBuf), pResultStr);

    /* 打印命令返回内容 */
    printf(szBuf);

    /* 不要忘记关闭句柄 */
    pclose(pResultStr);

    return 0;
    }

    输出

  • picture 1
  • 可见,多了一行total 16含义是

    popen函数

  • popen() 函数通过创建一个管道,调用 fork 产生一个子进程,执行一个 shell 以运行命令来开启一个进程。
  • 这个进程必须由 pclose() 函数关闭,而不是 fclose() 函数。pclose() 函数关闭标准 I/O 流,等待命令执行结束,然后返回 shell 的终止状态。如果 shell 不能被执行,则 pclose() 返回的终止状态与 shell 已执行 exit 一样。
  • 也就是,popen创建管道执行shell命令将文件流中的某些数据读出

    头文件和函数头

  • #include <stdio.h>
    FILE *popen(const char *command, const char *type);
  • command: 是一个指向以 NULL 结束的 shell 命令字符串的指针。命令将被传到 bin/sh 并使用 -c 标志shell 将执行这个命令,比如sh -c ls
  • type: 只能是读或者写中的一种,得到的返回值(标准 I/O 流)也具有和 type 相应的只读或只写类型。如果 type 是 “r” 则文件指针连接到 command 的标准输出;如果 type 是 “w” 则文件指针连接到 command 的标准输入。

    另一种方法

    作者:Reticence
    链接:https://www.zhihu.com/question/508000943/answer/2285530356
    来源:知乎
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    #include <stdio.h>
    #include <unistd.h>
    #include <string.h>

    int main() {
    char *argv[] = {"ls", NULL };
    int pipe_fd[2];
    char buffer[256];
    memset(buffer,0,256);
    pipe(pipe_fd); // 忽略了错误处理

    int pid = fork(); // 忽略了错误处理
    if (pid > 0) {
    sleep(1);
    close(pipe_fd[1]); // 关闭管道输出
    read(pipe_fd[0], buffer, 256); // ls的输出到buffer了,你可以进行你的处理
    printf("ls = %s",buffer);
    // 父进程
    } else {
    close(pipe_fd[0]); // 关闭管道读入
    dup2(pipe_fd[1], STDOUT_FILENO); // 关闭标准输出,改成管道输出
    execv("/usr/bin/ls", argv);
    }
    }

    管道开启和关闭

  • linux man手册参考
    #include <unistd.h>
    int pipe(int pipefd[2]);
  • 其中pipefd[0]是读一侧 pipefd[1]是写入一侧
  • 写入的时候要关闭读一侧,读的时候要关闭写入的一侧

    dup2用法

  • 转移输出定向
  • 参考链接

    文件描述符和FILE指针互相转换

  • 参考链接

    跨越进程的dup2(dup2与execv和execlp一起使用的问题)

  • 运行上述程序可见,主进程并不能抓取到输出
  • 然后做了以下测试,在子线程中直接讲execv修改为printf函数,结果发现主线程能抓取到printf函数的输出
  • 可以推测在execv创建新的线程之后,之前的dup2并不起到作用了
  • 但是发现使用execlp可以,使用execv不行,格式为execlp(argv[0], argv[0], argv[1], argv[2]);
    • 其中argv分别是echo, 输出的字符串NULL
  • 类似地,对execv函数的参数作出修改,还是没法收到,暂时不清楚原因
  • 最终版代码

    #include <stdio.h>
    #include <unistd.h>
    #include <string.h>

    int main()
    {
    char *argv[] = {"ls", "-l", NULL, NULL};

    // char *argv[] = {"echo", NULL, NULL};
    int pipe_fd[2];
    char buffer[256];
    char routeBuf[256];
    FILE* pipeWrite;
    getcwd(routeBuf, 256);
    // argv[2] = routeBuf;

    argv[1] = routeBuf;
    pipeWrite = fdopen(pipe_fd[1], "w");
    printf(argv[1]);
    printf("\n");
    memset(buffer, 0, 256);
    printf("pipe return: %d\n", pipe(pipe_fd)); // 忽略了错误处理

    int pid = fork(); // 忽略了错误处理
    if (pid > 0)
    {
    // sleep(1);
    wait();
    close(pipe_fd[1]); // 关闭管道输出
    printf("read: %d\n", read(pipe_fd[0], buffer, 256)); // ls的输出到buffer了,你可以进行你的处理
    printf("ls = \n%s\n", buffer);
    // 父进程
    }
    else
    {
    close(pipe_fd[0]); // 关闭管道读入
    // fflush(stdout);
    dup2(pipe_fd[1], STDOUT_FILENO); // 关闭标准输出,改成管道输出
    // fflush(stdout);
    // execv("/usr/bin/ls", argv);

    // execv("echo", argv);
    execlp(argv[0], argv[0], argv[1], argv[2]);
    // execlp(argv[0], argv[0], argv[1], argv[2]);
    // printf("test\n");
    fflush(pipeWrite);
    // close(pipe_fd[1]);
    }
    }
  • 输出:
    • picture 2
  • 上述代码修改参考链接

    python开启新的子进程并且获取命令行的返回值

  • 从python2.4版本开始,可以用subprocess这个模块来产生子进程,并连接到子进程的标准输入/输出/错误中去,还可以得到子进程的返回值。
  • 比如subprocess.Popen(command, stdout = subprocess.PIPE)
  • 去掉后面的手动指定参数,输出结果为
    • picture 3