在 Linux/Unix 环境下,有几种常用的方法可以创建子进程并执行外部命令,其中包括 fork-execl、system 和 popen。本文将深入介绍这三种方法的使用方法、参数说明和区别。
一、fork-execl 方法:
-
使用方法:
fork
:调用fork
函数创建一个新的子进程。- 在子进程中,调用
execl
函数(或其变种函数)来执行指定的外部命令。 - 子务。进程会调用
execl
函数来执行外部命令,此时父进程不受影响,可以继续执行其他任 - 虽然子进程正在执行外部命令,但父进程可以通过调用
wait
或waitpid
等函数来等待子进程的完成,并获取子进程的退出状态。 -
当父进程调用
wait
函数时,它会阻塞等待子进程的退出状态。父进程会一直等待,直到子进程结束并返回退出状态。这样做的目的是为了确保父进程在子进程完成后再继续执行。如果父进程没有调用
wait
函数,而是继续自己的执行流程,那么父进程和子进程将并发执行,互不等待。这可能会导致一些问题,例如父进程结束了但子进程仍在执行,造成子进程成为孤儿进程(即没有父进程管理),或者子进程结束后无法获取其退出状态。因此,对于使用
fork-execl
方法创建的子进程,通常建议父进程调用wait
函数来等待子进程的结束。这样可以确保父进程在子进程完成后再继续执行,并且可以获取到子进程的退出状态,以进行必要的处理。
-
参数说明:
fork
函数不接受任何参数。execl
函数原型为:int execl(const char *path, const char *arg0, ..., const char *argn, (char *)0);
path
:命令或可执行文件的路径。arg0
到argn
:外部命令的参数列表。(char *)0
:参数列表结束的标志。
-
区别:
fork-execl
实际上是两个独立的函数调用,fork
负责创建子进程,execl
负责执行外部命令。这种方式需要手动管理子进程的创建和退出,适合在需要更精细控制的场景下使用。execl
函数会直接替换当前进程的镜像,因此在调用execl
后的代码不会被执行,除非execl
失败。
二、system 方法:(相当于 fork+execl+wait)
-
使用方法:
- 调用
system
函数来执行指定的外部命令。 - 当父进程调用
system
函数来执行外部命令时,它会被阻塞,直到子进程执行完毕。 - 在子进程执行期间,父进程暂停执行其他任务,等待子进程结束。
- 一旦子进程执行完毕,父进程会恢复执行,可以继续执行其他任务。
- 调用
-
参数说明:
system
函数原型为:int system(const char *command);
command
:要执行的外部命令字符串。
-
区别:
system
函数将整个命令作为一个字符串参数传递,而不需要手动创建子进程。它会自动创建子进程,执行外部命令,并等待子进程结束。(相当于 fork+execl+wait);system
函数通过创建一个 Shell 进程来解析和执行命令。因此,可以使用 Shell 支持的各种特性和语法,如管道、重定向等。system
函数的返回值为外部命令的退出状态。
三、popen 方法:
-
使用方法:
- 调用
popen
函数来创建一个双向管道并启动一个子进程。 - 父进程在调用
popen
函数后,可以通过管道与子进程进行双向通信。 - 父进程可以在子进程执行期间向管道写入数据,供子进程读取。
- 父进程也可以从管道中读取子进程的输出数据。
- 父进程可以继续执行其他任务,但需要注意处理与子进程之间的通信
- 使用
fprintf
或fwrite
向子进程的标准输入发送数据。 - 使用
fscanf
或fread
从子进程的标准输出读取数据。 - 使用
pclose
关闭管道并等待子进程结束。
- 调用
-
参数说明:
popen
函数原型为:FILE *popen(const char *command, const char *type);
command
:要执行的外部命令字符串。type
:管道的读写模式,可以是 "r"(读取模式)或 "w"(写入模式)。
-
区别:
popen
函数创建了一个双向管道,允许父进程与子进程之间进行双向通信。- 父进程通过管道发送数据给子进程,并通过管道接收来自子进程的输出。
popen
函数返回一个文件指针,可以像操作普通文件一样使用该文件指针进行输入输出操作。pclose
函数用于关闭管道并等待子进程结束,并返回子进程的退出状态。
总结:
fork-execl
是两个独立的函数调用,需要手动管理子进程的创建和退出,适合在需要更精细控制的场景下使用。system
函数通过创建一个 Shell 进程来解析和执行命令,在简单的命令执行场景下使用方便。popen
函数创建双向管道,允许父进程与子进程之间进行双向通信,适合需要与子进程交换数据的场景。
所以实际上,在子进程执行期间,fork-execl
方法允许父进程继续执行其他任务,而 system
方法会暂停父进程的执行。这是两种不同的行为方式。
无论哪种方法,当子进程执行完毕后:
- 对于
fork-execl
方法,子进程结束后会回到父进程继续执行代码。 - 对于
system
方法,父进程会在子进程结束后恢复执行。 - 对于
popen
方法,父进程可以通过调用pclose
函数来关闭管道并等待子进程的结束。然后父进程继续执行其他任务。
对于只执行外部命令并等待其结束的情况,可以使用 system
函数或 popen
函数来实现。system
函数会阻塞父进程直到子进程执行完毕,而 popen
函数允许父进程与子进程进行双向通信。(popen是阻塞型)
20230816