Linux 调用可执行程序
- 1. `system()` 函数
- 1.1 `system()` 函数的声明
- 1.2 `system()` 函数的不同场景返回值
- 1.3 `system()` 函数的代码示例
- 2. `exec()` 函数族
- 2.1 `exec()` 函数族的声明
- 2.2 `exec()` 函数族执行失败的情况
- 2.3 `exec()` 函数族的代码示例
- 3. `exec()` 与 `system()` 的区别以及使用注意事项
- 4. `exec()` 会创建新进程吗?新进程与原进程的关系
- 5. 总结
在 Linux 系统中,我们经常需要在一个程序中调用另一个可执行程序。这可以通过多种方式实现,其中最常用的两种方式是使用 system()
函数和 exec()
函数族
1. system()
函数
1.1 system()
函数的声明
system()
函数的声明如下:
#include <stdlib.h>
int system(const char *command);
1.2 system()
函数的不同场景返回值
system()
函数用于执行一个 shell 命令。它的返回值表示命令执行的退出状态。
- 正常情况下,
system()
函数返回执行的 shell 命令的退出状态。通常,0 表示成功,非 0 值表示失败。 - 如果
system()
函数调用失败(例如,无法创建子进程或执行 shell 命令),则返回 -1。
1.3 system()
函数的代码示例
#include <stdio.h>
#include <stdlib.h>
int main() {
int ret = system("ls -l"); // 执行 ls -l 命令
if (ret == 0) {
printf("命令执行成功\n");
} else if (ret == -1) {
perror("system() 调用失败");
} else {
printf("命令执行失败,退出状态为 %d\n", ret);
}
return 0;
}
2. exec()
函数族
2.1 exec()
函数族的声明
exec()
函数族是一组函数,它们用于替换当前进程的映像,执行一个新的程序。exec()
函数族有很多不同的变体,它们的声明和参数略有不同,但功能基本相同。
以下是几个常用的 exec()
函数:
#include <unistd.h>
int execl(const char *path, const char *arg0, ..., NULL);
int execlp(const char *file, const char *arg0, ..., NULL);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
2.2 exec()
函数族执行失败的情况
如果 exec()
函数族执行失败,则返回 -1,并设置 errno
来指示错误类型。常见的错误原因包括:
- 文件不存在:指定的程序文件不存在。
- 权限不足:当前用户没有执行指定程序的权限。
- 内存不足:无法加载新的程序映像。
- 参数错误:传递给
exec()
函数的参数不正确。
2.3 exec()
函数族的代码示例
#include <stdio.h>
#include <unistd.h>
int main() {
// 使用 execlp() 函数执行 ls -l 命令
execlp("ls", "ls", "-l", NULL);
// 如果 execlp() 执行失败,则会执行以下代码
perror("execlp() 调用失败");
return 1; // 返回 1 表示程序执行失败
}
3. exec()
与 system()
的区别以及使用注意事项
- 功能:
system()
函数用于执行一个 shell 命令,而exec()
函数族用于替换当前进程的映像,执行一个新的程序。 - 返回值:
system()
函数返回执行的 shell 命令的退出状态,而exec()
函数族如果执行成功则不会返回,如果执行失败则返回 -1。 - 进程:
system()
函数会创建一个新的子进程来执行 shell 命令,而exec()
函数族则直接在当前进程中执行新的程序。
使用注意事项:
- 由于
system()
函数会创建一个新的子进程,因此开销比exec()
函数族要大。 system()
函数执行的 shell 命令可能会受到 shell 注入攻击,因此应该避免使用用户提供的输入作为命令字符串。exec()
函数族执行成功后,原进程的代码将不再执行,因此需要在调用exec()
函数族之前做好必要的清理工作。
4. exec()
会创建新进程吗?新进程与原进程的关系
exec()
函数族不会创建新的进程。它会替换当前进程的映像,执行一个新的程序。这意味着原进程的代码、数据和堆栈都会被新的程序所覆盖。
新程序与原进程的关系:
- 进程 ID:新程序的进程 ID 与原进程相同。
- 父进程:新程序的父进程与原进程相同。
- 环境变量:新程序会继承原进程的环境变量。
- 文件描述符:新程序会继承原进程打开的文件描述符。
5. 总结
system()
函数和 exec()
函数族都是在 Linux 中调用可执行程序的常用方法。system()
函数使用简单,但开销较大,且存在安全风险;exec()
函数族效率高,但使用稍复杂