我目前正在阅读并试验在Linux上使用C代码运行程序的各种可能性。我的用例涵盖了所有可能的场景,从简单地运行和忘记一个过程,阅读或写入过程,到阅读和写入它。
对于前三个,popen()
非常易于使用且效果很好。我知道它在内部使用了某个版本的fork()
和exec()
,然后调用shell来实际运行命令。
对于第三种情况,popen()
不是一个选项,因为它是单向的。可用选项包括:
fork()
和exec()
,加上pipe()
和dup2()
输入/输出posix_spawn()
,内部使用上述内容作为需要我注意到这些可以达到与popen()
相同的效果,但我们可以完全避免调用额外的sh
。这听起来很可取,因为它似乎不太复杂。
但是,我注意到,即使我在互联网上发现的examples on posix_spawn()
确实调用了一个shell,所以它似乎必然会带来好处。如果它是关于解析命令行参数,wordexp()
似乎也做得同样好。
调用shell运行所需进程而不是直接运行它的好处背后的原因是什么?
编辑:我意识到我对这个问题的措辞并没有完全反映我的实际兴趣 - 我对通过{{ 的好处更加好奇1}}而不是(历史)原因,虽然两者明显相关,但两种变体的答案同样相关。
答案 0 :(得分:5)
调用shell允许您执行在shell中可以执行的所有操作。 例如,
Chrome
使用FILE *fp = popen("ls *", "r");
可以(展开当前目录中的所有文件)。 将其与:
进行比较popen()
您不能以execvp("/bin/ls", (char *[]){"/bin/ls", "*", NULL});
作为参数执行ls
,因为*
将按字面解释exec(2)
。
同样,*
可以使用管道(|
),重定向(>
,<
,......)等。
否则,如果您不需要shell,则没有理由使用popen
- 这是不必要的。你最终会得到一个额外的shell进程,所有在shell中出错的东西都可能在你的程序中出错(例如,你传递的命令可能被shell错误地解释并且存在一个常见的安全问题)。 popen()
is designed that way。 popen
+ fork
解决方案更清晰,没有与shell相关的问题。
答案 1 :(得分:3)
滑稽的答案是因为POSIX标准(http://pubs.opengroup.org/onlinepubs/9699919799/functions/popen.html)这样说。或者更确切地说,它表示它的行为应该像命令参数传递给/ bin / sh进行解释一样。
所以我认为一致的实现原则上也可以有一些内部库函数来解释shell命令,而不必分叉和执行单独的shell进程。我实际上并没有意识到任何这样的实现,我怀疑所有的角落情况都是正确的。
答案 2 :(得分:2)
The 2004 version of the POSIX system()
documentation的基本原理也可能适用于popen()
。请注意system()
所述的限制,尤其是说明进程ID不同的一个&#34;:
<强> 基本原理 强>
...
system()函数有三个级别的规范。该 ISO C标准给出了最基本的标准。它需要这个功能 存在,并为应用程序定义一种查询方式 命令语言解释器存在。它没有说明命令 语言或解释命令的环境。
IEEE Std 1003.1-2001对system()施加了额外的限制。它 要求如果有命令语言解释器, 环境必须是fork()和exec指定的。这确保了 例如,close-on-exec有效,文件锁不会被继承, 并且进程ID不同。它还指定了回报 当命令行可以运行时,来自system()的值,从而给出 申请一些关于命令完成状态的信息。
最后,IEEE Std 1003.1-2001要求解释命令 与Shell和Utilities中定义的shell命令语言一样 IEEE Std 1003.1-2001的数量。
请注意对&#34; ISO C标准&#34;的多次引用。 The latest version of the C standard要求命令字符串由系统&#34;命令处理器&#34;处理:
7.22.4.8
system
功能概要
#include <stdlib.h> int system(const char *string);
<强>描述强>
如果
string
是空指针,则system
函数确定 主机环境是否有命令处理器。如果string
不是空指针,system
函数传递字符串string
指向要执行的命令处理器 以实施方式记录的方式;这可能会 导致调用system
的程序在不符合的情况下运行 方式或终止。<强>返回强>
如果参数是空指针,则为
system
函数 仅当命令处理器可用时才返回非零值。如果 参数不是空指针和system
函数 确实返回,它返回一个实现定义的值。
由于C标准要求系统&#34;命令处理器&#34;用于system()
电话,我怀疑:
popen()
与system()
实施联系起来。所以这是两次删除的滑稽答案。