linux system 和 execl 函数对比
1. system()函数
1.1 system 函数的具体执行步骤
实际上,system也是调用了exec函数去执行一个系统命令,可以把system函数理解成对exec函数的一个包装
system函数的具体执行步骤是这样的:
1.fork一个子进程;
2.在子进程中调用exec函数去执行command;
3.在父进程中调用wait去等待子进程结束。
创建出一个子进程,然后在子进程中用exec来执行命令
创建出一个子进程,然后在子进程中用exec来执行命令,即是子进程成功执行了没返回也没关系,还有父进程可以返回嘛!
对于fork失败,system()函数返回-1。
如果exec执行成功,也即command顺利执行完毕,则返回command通过exit或return返回的值。
1.1.1 system 源码实现
int system(const char * cmdstring)
{
pid_t pid;
int status;
if(cmdstring == NULL)
{
return (1); //如果cmdstring为空,返回非零值,一般为1
}
if((pid = fork())<0)
{
status = -1; //fork失败,返回-1
}else if(pid == 0)
{
execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);
_exit(127); // exec执行失败返回127,注意exec只在失败时才返回现在的进程,成功的话现在的进程就不存在啦~~
}else //父进程
{
while(waitpid(pid, &status, 0) < 0)
{
if(errno != EINTR)
{
status = -1; //如果waitpid被信号中断,则返回-1
break;
}
}
}
return status; //如果waitpid成功,则返回子进程的返回状态
}
1.2 system 执行成功
#include <stdio.h>
#include <errno.h>
int main(int argc, char* argv[]){
int a = system("/bin/ls -l");;
printf("%d,errno=%d\n", a,errno);
printf("exiting...\n");
return 0;
}
结果:
[root@glusterfs home]# gcc sys.c -o sys
[root@glusterfs home]# ./sys
total 32
-rwxr-xr-x 1 root root 8648 Dec 2 17:17 a.out
-rwxr-xr-x 1 root root 8648 Dec 2 17:32 sys
-rw-r--r-- 1 root root 195 Dec 2 17:31 sys.c
-rw-r--r-- 1 root root 307 Dec 2 17:17 test.c
0,errno=0
exiting...
[root@glusterfs home]#
1.3 system 执行成功,但命令未执行成功
#include <stdio.h>
#include <errno.h>
int main(int argc, char* argv[]){
int a = system("/bin/rm 1.txt");;
printf("%d,errno=%d\n", a,errno);
printf("exiting...\n");
return 0;
}
结果:
[root@glusterfs home]# gcc -o sys sys.c
[root@glusterfs home]# ./sys
/bin/rm: cannot remove ‘1.txt’: No such file or directory
256,errno=0
exiting...
[root@glusterfs home]#
1.4 system 执行成功,但命令执行失败
#include <stdio.h>
#include <errno.h>
int main(int argc, char* argv[]){
int a = system("123 456");;
printf("%d,errno=%d\n", a,errno);
printf("exiting...\n");
return 0;
}
结果:
[root@glusterfs home]# gcc -o sys sys.c
[root@glusterfs home]# ./sys
sh: 123: command not found
32512,errno=0
exiting...
[root@glusterfs home]#
2. execl 成功不会返回,命令执行失败返回-1
2.1 execl 执行成功不返回
原因:
在进程的创建上Unix采用了一个独特的方法,它将进程创建与加载一个新进程映象分离。
execl将当前进程替换掉,所有最后那条打印语句不会输出
利用execl将当前进程main替换掉,所有最后那条打印语句不会输出
2.1.1 exec 重要说明!!!
exec函数会取代执行它的进程, 也就是说, 一旦exec函数执行成功, 它就不会返回了, 进程结束.
但是如果exec函数执行失败, 它会返回失败的信息, 而且进程继续执行后面的代码!
通常exec会放在fork() 函数的子进程部分, 来替代子进程执行啦, 执行成功后子程序就会消失, 但是执行失败的话, 必须用exit()函数来让子进程退出!
#include <stdio.h>
int main(int argc, char* argv[]){
int a = execl("/bin/ls", "ls", "-l", NULL);
printf("%d\n", a);
printf("exiting...\n");
return 0;
}
root@glusterfs home]# gcc test.c
[root@glusterfs home]# ll
total 16
-rwxr-xr-x 1 root root 8584 Dec 2 17:10 a.out
-rw-r--r-- 1 root root 175 Dec 2 17:10 test.c
[root@glusterfs home]# ./a.out
total 16
-rwxr-xr-x 1 root root 8584 Dec 2 17:10 a.out
-rw-r--r-- 1 root root 175 Dec 2 17:10 test.c
[root@glusterfs home]#
execl 执行后没有返回,没有打印代码中的值
2.1.2 execl + fork 返回信息
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
int main(int argc, char* argv[]){
int childpid;
pid_t pid;
pid = fork();
if(pid > 0)
{
printf("parent execl done\n");
wait(&childpid);
}else if(0 == pid)
{
execl("/bin/ls", "ls", "-l", NULL);
printf("pid execl done\n");
}else{
printf("error pid < 0 \n");
}
printf("exiting...\n");
return 0;
}
结果:
[root@glusterfs home]# gcc test.c
[root@glusterfs home]# ./a.out
parent execl done
total 52
-rwxr-xr-x 1 root root 8632 Dec 3 14:14 a.out
-rw-r--r-- 1 root root 444 Dec 3 14:14 test.c
exiting...
[root@glusterfs home]#
2.2 execl 命令执行成功,内容失败,表示成功,不返回
执行成功的意思是这条命令本身没错,但是这条命令成不成功exec管不了,他只负责执行
比如说"rm 1.txt",这条指令是正确的,即使没有1.txt这个文件报了无法删除1.txt文件,exec函数还是算执行成功,不会有返回。
#include <stdio.h>
int main(int argc, char* argv[]){
int a = execl("/bin/rm", "rm", "1.txt", NULL);
printf("%d\n", a);
printf("exiting...\n");
return 0;
}
[root@glusterfs home]# gcc test.c
[root@glusterfs home]# ./a.out
rm: cannot remove ‘1.txt’: No such file or directory
[root@glusterfs home]#
2.3 execl 执行失败则直接返回-1,失败原因存于errno中
#include <stdio.h>
#include <errno.h>
int main(int argc, char* argv[]){
int a = execl("hani", "1", "2", NULL);
printf("%d,errno=%d\n", a,errno);
printf("exiting...\n");
return 0;
}
结果:
[root@glusterfs home]# gcc test.c
[root@glusterfs home]# ./a.out
-1,errno=2
exiting...
[root@glusterfs home]#
#define ENOENT 2 /* No such file or directory */
3. 总结:system 没有 exec 效率高
关于system 有一段这样的介绍: system 执行时内部会自动启用fork() 新建1个进程, 效率没有直接使用fork() 和 exec函数高.