popen返回的FILE在使用fgets时出错

5

我尝试在我的C代码中执行命令行,但当我到达fgets()函数时,出现了NULL错误。

void executeCommand(char* cmd, char* output) {
    FILE *fcommand;
    char command_result[1000];
    fcommand = popen(cmd, "r");
    if (fcommand == NULL) {
        printf("Fail: %s\n", cmd);
    } else {
        if (fgets(command_result, (sizeof(command_result)-1), fcommand) == NULL)
             printf("Error !");
        strcpy(output, command_result);
    }
    pclose(fcommand);
}

我的命令是:

java -jar <parameters>

尽管在终端上执行相同命令时结果如预期,为什么fgets返回的结果是NULL?


2
fgets调用失败后,调用feof(fcommand)ferror(fcommand)会得到什么结果? - Sander De Dycker
对于 feof(fcommand) 返回 1,对于 ferror(fcommand) 返回 0。 - TheForbidden
1个回答

4

fgets()函数从流中读取不超过size-1个字符,并将它们存储到指向缓冲区s的指针中。当遇到EOF或换行符时,读取操作停止,如果读取到换行符,则同时将其存储到缓冲区中。一个'\0'字符被存储在缓冲区中最后一个字符之后。

简单来说,popen()函数会调用fork()函数,而你试图在由cmd参数调用的程序生成输出之前读取管道,因此管道上没有数据,第一次读取管道时将返回EOF,因此fgets()函数无法获取数据并返回。你需要睡眠、轮询或进行阻塞读取操作。


睡觉?在哪里?在popen和fgets之间吗? - TheForbidden
2
是的...但是sleep是最糟糕的解决方案,因为它要么(a)有可能在输出准备好之前就被唤醒,要么(b)让用户等待很长时间后才输出。最好的答案是对管道进行阻塞读取。 - K Scott Piel
1
你确定吗?我的理解是,读取操作会一直阻塞,直到管道中有数据。只有当另一个程序关闭其管道时,读取操作才会返回EOF。我认为这就是使用管道的全部意义所在,但我可能错了。对于最初的问题,我怀疑执行操作失败了。你的程序是否与命令行具有相同的环境?没有更改路径等操作吗? - Sodved
fgets()是一种非阻塞读取函数,无论从哪个流中读取都可以。 - K Scott Piel
@Sodved,在另一个独立的C文件中,它甚至可以在终端上完美运行。 - TheForbidden
@KScottPiel 不,sleep没有起作用,实际上popen返回一个成功的返回代码,因此读取命令并执行它没有问题。阻塞读取也不起作用。 - TheForbidden

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接