C 编程/stdlib.h/system
在 C 标准库中,system 是一个用于执行子进程和命令的函数。它在 stdlib.h
头文件中定义。它与 exec
/spawn
函数系列的不同之处在于,它不是将参数传递给执行的对象,而是将单个字符串传递给系统 shell,通常是 POSIX shell,/bin/sh -c
。
int system (const char *command);
system
函数是阻塞的;也就是说,调用将等待直到子进程终止并返回其退出值。在此期间,SIGCHLD
将被阻塞,因为 system
等待子进程死亡;此外,SIGINT
和 SIGQUIT
被忽略,因此为了确保响应性,程序员应该检查返回值以查看用户是否试图终止进程。发生错误时,system 在 fork
之前或期间(例如,进程计数限制已达到)失败时将返回 -1,但在 fork
之后(例如,无法执行 sh)失败时将返回 127;这与命令以状态 127 退出无法区分。
在 POSIX 中,system
使用两个参数: “-c
” 和 command
分叉并执行 /bin/sh
。虽然 sh 的行为在其他地方有规定,但需要注意的是 command
不必是单个命令;它实际上可以是一个管道,甚至是一系列管道。例如,考虑一个希望显示屏幕截图的程序
system ("pngtopnm \"My Screenshot.png\" | pnmtoxwd > out.xwd && xwud out.xwd");
这行展示了一个重要的考虑因素:由于 command
将被解析为 shell 命令行,因此围绕例如文件名引号必须转义。然而,这会引发安全问题,因为如果 command
是从用户提供的 数据构建的,攻击者可能能够跳出任何引号并在父级上下文中执行任意命令;事实上,这几乎是规范的代码注入漏洞。因此,建议仅对预先确定的命令字符串使用 system
,使用其他函数(spawn
等)在 argv 中传递用户提供的数据,或通过管道或临时文件传递此类数据。
由 system
生成的子进程继承其父进程的标准流;因此,子进程可以接收键盘输入并写入终端。请注意,这意味着父进程不会接收子进程的输出,除非使用重定向或 tee。
- Linux 库函数 手册 : 执行一个 shell 命令 –
- C++ 参考资料
std::system