1.执行一个新程序
linux下,使用exec函数执行一个新程序,该函数在文件系统中搜索要执行文件,并将该文件内容复制到调用exec函数的地址空间,取代原进程的内容,即覆盖从父进程中复制来的数据。
#include <unistd.h>
int execl(const char * pathname,const char * arg0,……);
int execle(const char * pathname,const char * arg0,……/*char * const envp[]*/);
int execv(const char * pathname,char * const argv[]);
int execve(const char * pathname,char * const argv[],char * const envp[]);
execlp(const char * filename,const char * arg0,……);
int execvp(const char * filename,char * const argv[]);
其中l表示list,说明参数以列表的形式提供,并且以NULL结尾,但是参数个数没有限制。
eg:
char * arg0,char * arg1,char * arg2,NULL
v表示vecter,说明参数一二维数组的形式提供。这个数组每一行是一个参数
e表示传递给程序环境变量列表,这是一个二维数组。这个数组每一行是一个环境变量。如果没有显式的传递,则新程序将复制父进程的环境表。
以p结尾的表示第一个参数不是完整的路径名称,而是一个程序名。这样,就余姚从环境表中的PATH变量中取出每一项,于第一个参数组合成一个完整的路径
eg:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
pid_t pid;
pid = fork();
if(pid < 0){
printf("fail to fork/n");
exit(1);
}else if(pid == 0){
if(execvp("ls", NULL) < 0){
printf("fail to exec/n");
exit(0);
}
/*这里应该永远不会执行,因为已被ls程序的代码段所取代了*/
printf("the child is not hello/n");
exit(0);
}
printf("the parent/n");
return 0;
}
结果:
alei@alei-desktop:~/linux/code/chapter_11(done)$ gcc exec.c -o exec
alei@alei-desktop:~/linux/code/chapter_11(done)$ ./exec
the parent
err_vfork exec.c fork.c nozombie.c vfork.c zombie.c
err_vfork.c exec.c~ mul_process.c system.c wait3.c
exec fork mul_process.c~ vfork wait.c
2.执行解释器文件
解释器文件是文本文件,这种文件的起始形式是:
#! 解释器程序的路径 解释器程序所需要的参数
如shell脚本,其开始为:
#! /bin/sh
如果程序是一般程序。这个解释器只能包含第一行
例如,运行test文件,该解释器文件只能有一行
#! /home/demo/test
使用exec函数执行此脚本,和直接在shell中输入“/home/demo/test”效果是一样的。
下面是一个例子:
(1)编写如下程序
//echoargs.c
#include <stdio.h>
int main(int argc,char * argv[])
{
int i;
for(i=0;i<argc;i++){
printf("argv[%d] : %s/n",i,argv[i]);
}
return 0;
}
(2)编译程序
gcc echoargs.c -o echoargs
(3)将可执行文件服知道/home/demo/目录中
cp echoargs /home/demo
(4)编辑解释器脚本,存为interp.sh
#! /home/demo/echoargs testarg
#解释器文件interp,出第一行之外,其余的行都是注释
#第二参数是故意加上的测试参数,其本身对程序没有任何影响
(5)将该文家改为可执行
chmod u+x interp.sh
(6)再编写调用该脚本的程序
//run_script.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
pid_t pid;
pid=fork();
if(pid<0){
perror("fail to fork");
exit(1);
}else if(pid==0){
execl("/home/demo/interp.sh","interp","arg1","arg2",NULL);
exit(0);
}
exit(0);
}
(7).编译该程序
gcc run_script.c -o script
(8)运行该程序
argv[0] : /home/alei/demo/echoargs
argv[1] : testarg
argv[2] : /home/alei/demo/interp.sh
argv[3] : arg1
argv[4] : arg2
第一行是整个解释器文件的路径,第二行是测试使用的无用参数,后面是调用exec是传递的参数。由此可知,exec函数中传给新程序的命令行参数和解释器文件中的命令行参数一起作为参数船歌解释器程序,顺序是解释器文件中的命令行参数在前,exec函数中传给新程序的命令行参数在后。
3.在程序中执行shell命令
Linux环境下使用system函数调用shell命令,其函数原型如下:
#include <stdlib.h>
int system(const char * cmdstring);
eg:
//system.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#define MAX 1024
int main(void)
{
int fd;
char buf[MAX];
int n;
if(system("ls > temp.txt") == -1){
perror("fail to exec command");
exit(1);
}
if(fd = open("temp.txt", O_RDWR) == -1){
perror("fail to open");
exit(1);
}
if((n = read(fd, buf, MAX)) == -1){
perror("fail to read");
exit(1);
}
buf[n] = '/0';
printf("%s", buf);
return 0;
}