在Linux C调用系统命令
在开发中时不时会在代码中调用系统命令,Linux 中调用系统命令的方法比较多。是否需要获取命令的输出也需要考虑。
exec函数系列
exec 函数系列是指以 exec 为开头用来执行Shell命令的几个函数。
1 |
|
system
函数定义如下:
1 |
|
在其中会使用 fork() 调用 execl() 函数,最后执行函数
返回值
- 如果参数
command为NULL,则在 shell 可用的情况下为非零值,在没有 shell 可用的情况下为0。 - 如果无法
fork子进程则返回-1,并且将errno设置为错误值。 - 如果命令无法执行则返回
127 - 如果可以执行直接返回执行结果
popen
popen() 是一种更方便的“运行命令并拿到输出”的方式。
popen 函数
函数定义如下:
1 |
|
它做了两件事:
- 启动一个子进程去执行你传进来的
command - 根据
type把子进程和当前进程连起来,让你可以像读写文件一样读/写命令的标准输入/标准输出
type 常见取值
r:你从popen()返回的FILE *里读取命令的输出(子进程的stdout)w:你向FILE *写入内容(子进程的stdin)
返回值怎么理解
popen()成功:返回一个FILE *popen()失败:返回NULL,并设置errno表示错误原因pclose():关闭这个“管道”,并等待子进程结束;一般情况下返回子进程的结束状态;如果pclose()本身失败(例如参数不合法等),通常会返回-1并设置errno
如果你只是需要“能不能跑完”,一般判断 pclose() 是否为非零也够用;如果你想拿到更精确的退出码,再结合 sys/wait.h 里的宏做进一步判断。
示例:读取命令输出
下面这个例子会执行 ls -l,并把输出逐行打印出来:
1 |
|
普通选择建议
- 只要“执行一下命令”但不关心输出:优先用
system() - 想“读取命令输出”(例如把
command的结果拿来解析):用popen(..., "r") - 你的命令参数里包含用户输入、或者不希望走 shell:考虑用
exec*系列配合fork(),自己处理参数和管道(更稳、更安全)
顺便提醒一句:system() 和 popen() 都会走 shell(对很多场景来说方便,但也更容易受到转义/注入问题影响)。如果 command 来自不可信输入,尽量不要直接拼接字符串。