You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

popen()执行逻辑与sh -c cmdstring不符的原因排查

关于popen执行逻辑的误解分析

测试场景

我测试了《UNIX环境高级编程(第3版)》(APUE)15.3节中popen和pclose函数的示例代码,代码如下:

#include "apue.h"
#include <sys/wait.h>

#define PAGER   "${PAGER:-more}" /* environment variable, or default */

int
main(int argc, char *argv[])
{
    char    line[MAXLINE];
    FILE    *fpin, *fpout;

    if (argc != 2)
        err_quit("usage: a.out <pathname>");
    if ((fpin = fopen(argv[1], "r")) == NULL)
        err_sys("can't open %s", argv[1]);

    if ((fpout = popen(PAGER, "w")) == NULL)
        err_sys("popen error");

    /* copy argv[1] to pager */
    while (fgets(line, MAXLINE, fpin) != NULL) {
        if (fputs(line, fpout) == EOF)
            err_sys("fputs error to pipe");
    }
    if (ferror(fpin))
        err_sys("fgets error");
    if (pclose(fpout) == -1)
        err_sys("pclose error");

    exit(0);
}

输入文件temp.in的内容:

$ cat temp.in
test sentence

程序运行输出:

$ ./popen2 temp.in 
test sentence

问题疑惑

根据APUE所述,执行fpout = popen(cmdstring, "w")等效于子进程执行sh -c cmdstring。因此我认为上述代码中的popen应执行:

sh -c "${PAGER:-more} test sentence"

我的操作系统(Ubuntu 22.04.3 LTS)未设置PAGER环境变量,因此实际应执行:

sh -c "more test sentence"

但more命令的参数应该是文件名,直接执行以下命令会报错:

$ ${PAGER:-more} temp.in 
test sentence
$ ${PAGER:-more} test sentence
more: can't open test: no such file or directory
more: can't open sentence: no such file or directory

我的推论哪里出错了?

错误原因分析

你的核心误解在于混淆了popen的执行逻辑和数据传递方式:

  • popen(PAGER, "w")执行的是sh -c "${PAGER:-more}",而非你以为的sh -c "${PAGER:-more} test sentence"。这里的cmdstring就是${PAGER:-more},并没有把文件内容作为命令参数传递给more。
  • 程序中通过fputs写入fpout的内容,是通过管道传递给more的标准输入,而非作为命令行参数。当more没有接收到文件名参数时,默认会从标准输入读取内容,这就是程序能正常输出的原因。
  • 你手动执行${PAGER:-more} test sentence时,test和sentence被当作文件名参数,自然会报错;但程序里的more是从管道读数据,和直接传文件名是两种完全不同的输入方式。

简单来说,程序的逻辑是:打开文件→通过管道把文件内容传给more的标准输入→more读取标准输入并显示,而非把文件内容作为参数传给more。

内容的提问来源于stack exchange,提问作者JiangZiyang

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 12:52:57