Linux系统编程与网络编程——exec执行其它程序,实现自己的shell(九)

执行其他程序

我们派生一个子进程来完成某项工作的时候,经常需要让另外一个程序来完成。函数exec()可以用来执行一个可执行文件来代替当前进程的执行映像。需要注意的是,该调用并没有生成新的进程,而是在原有进程的基础上,替换原有进程的正文,调用前后是同一个进程,进程号PID不变,但执行的程序变了。在Linux中,有6种调用的形式,他们的函数原型如下:
在这里插入图片描述
exec()的六个函数实现的功能是一样的,只是在传递参数和设置环境变量方面提供了不同的方式。6个函数都是以exec四个字母开头的,后面的字母表示了其用法上的区别:

表明后面的参数列表是要传递给程序的参数列表,参数列表的第一个参数
在这里插入图片描述
事实上,只有execve是真正的系统调用,其它五个函数最终都调用execve,所以execve在man手册第2节,其它函数在man手册第3节。这些函数之间的关系如下图所示。
在这里插入图片描述
用execl()执行一个程序,源代码execl_test.c

#include <stdio.h>
#include <unistd.h>

extern char **environ;

int main(int argc, char** argv)
{
	char* arg[3];
	arg[0] = "/bin/ls";
	arg[1] = "/";
	arg[2] = NULL;
	printf("this is execl test\n");
	execl(arg[0], arg[1], arg[2]);
	printf("running after the execvp() call");
	return 0;
}

从输出来看,execl()执行了新的程序,代替了当前进程的程序,因此除非execl()调用失败,否则后面的代码永远不会被调用
在这里插入图片描述
用execvp执行一个程序,源代码:execvp_test.c

#include <stdio.h>
#include <unistd.h>

int main(int argc, char** argv)
{
	char* arg[3];
	arg[0] = "ls";
	arg[1] = "/";
	arg[2] = NULL;
	printf("this is execvp test\n");
	execvp("ls", arg);
	return 0;
}

第一个参数由 /bin/ls 变成了 ls ,第二个参数是一个字符串数组。运行结果与execl_test的一模一样。

exec函数通常和fork()一起配合使用,由fork派生一个子进程,在子进程执行新的程序。例如:

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
int main(int argc, char** argv)
{
	int ret;
	pid_t pid;
	pid_t pid_c;
	pid = fork();
	if(pid == 0)
	{
		printf("child PID=[%d]\n", getpid());
		execlp("ls", "ls", "-ls", NULL);
	}
	else if(pid != -1)
	{
		pid_c = wait(&ret)
		printf("child PID=[%d] wait return = [%d]\n", pid_c, ret);
	}
	return 0;
}

实现一个自己的shell

#include <sys/wait.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main(int argc, char** argv)
{
	pid_t pid;
	char buf[1024];
	char * arg[10];
	int i, ret;
	AGAIN:
	/*读取命令行*/
	printf("myshell:%s$", getcwd(NULL, 1024));
	fflush(stdout);
	ret = read(STDIN_FILENO, buf, sizeof(buf) - 1);
	if(ret == -1)
	{
		perror("read");
		exit(1);
	}
	buf[ret - 1] = '\0';
	/*处理exit命令*/
	if(strcmp(buf, "exit") == 0)
	{
		exit(0);
	}
	/*分割参数*/
	i = 0;
	arg[i] = strtok(buf, " ");
	while(arg[i] != NULL)
	{
		if(++i >= sizeof(arg))
			break;
		arg[i] = strtok(NULL, " ");
	}
	/*处理cd命令*/
	if(i == 2 && strcmp(arg[0], "cd") == 0)
	{
		chdir(arg[1]);
		goto AGAIN;
	}
	/*处理其他命令*/
	pid = fork();
	if(pid == 0)
	{
		execvp(arg[0], arg);
		return 0;
	}
	else if(pid != -1)
	{
		wait(NULL);
		goto AGAIN;
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Gsunshine24/article/details/88983217