您的位置:首页 > 运维架构 > Shell

关于一个简单的shell的实现

2013-09-23 14:12 706 查看
题目是操作系统书上的,很无聊,就做了做!

做的时候遇到了一些问题,查了一些资料,现在集中展现一下。

1.关于exec族

execvp

表头文件:

#include<unistd.h>

定义函数:

int execvp(const char *file ,char * const argv []);

函数说明:

execvp()会从PATH 环境变量所指的目录中查找符合参数file 的文件名,找到后便执行该文件,然后将第二个参数argv传给该欲执行的文件。

返回值:

如果执行成功则函数不会返回,执行失败则直接返回-1,失败原因存于errno中。

execl

表头文件:

Windows下头文件:#include <process.h>

Linux下头文件:#include <unistd.h>

函数定义:

int execl(const char *path, const char *arg, ...);

函数说明:

execl()其中后缀"l"代表list也就是参数列表的意思,第一参数path字符指针所,指向要执行的文件路径, 接下来的参数代表执行该文件时传递的参数列表:argv[0],argv[1]... 最后一个参数须用空指针NULL作结束。

返回值 :

成功则不返回值, 失败返回-1, 失败原因存于errno中,可通过perror()打印。

execle

表头文件:

#include<unistd.h>

定义函数:

int execle(const char * path,const char * arg,....,char *const envp[]);

函数说明:

execl()用来执行参数path字符串所代表的文件路径,并为新程序复制最后一个参数所指示的环境变量。接下来的参数代表执行该文件时传递过去的argv(0)、argv[1]……,最后一个参数必须用空指针(NULL)作结束。

返回值:

如果执行成功则函数不会返回,执行失败则直接返回-1,失败原因存于errno中。

execve

定义函数:

int execve(const char * filename,char * const argv[ ],char * const envp[ ]);

函数说明:

execve()用来执行参数filename字符串所代表的文件路径,第二个参数是利用数组指针来传递给执行文件,并且需要以空指针(NULL)结束,最后一个参数则为传递给执行文件的新环境变量数组。

返回值:

如果执行成功则函数不会返回,执行失败则直接返回-1,失败原因存于errno 中。


2.关于为什么要创建子进程运行输入命令的原因!

先看下面一段代码:

#include <stdio.h>
#include <unistd.h>
#include <wait.h>
#define MAXLINE 80

void setup (char inputBuffer[], char *argv[])
{

    int i, j;
	char *p;
    i = 0;
    for (p = inputBuffer; ;p++)/*将字符命令一段一段拆分开来,如输入ls -l,则argv[0]= "ls",argv[1]="-l",argv[2]=NULL*/
	{
		argv[i++] = p;
		while (*p != ' ' && *p != '\0')
			p++;
        if (*p == '\0')
		{
			break;
		}
		*p = '\0';
   	}
    argv[i] = NULL;/*最后一个参数须用空指针NULL作结束*/
    execvp (argv[0], argv);/*执行命令,argv[0]放着执行的命令,其余的argv放着参数*/
}

int main()
{

	char inputBuffer[MAXLINE];
	char *argv[MAXLINE / 2 - 1];

	while (1)
	{
		printf ("COMMAND->");
  		gets (inputBuffer);/*输入命令*/
		setup (inputBuffer, argv);
                printf ("扑街!");
	}
	return 0;
}


如果我们输入 ls -l的话,会列出该目录的文件夹,但是就结束了,主程序的“扑街!”并未有输出!原因在于:execvp函数,execvp如果执行成功则函数不会返回,执行失败则直接返回-1,失败原因存于errno中。由于执行成功了,这个进程就结束了,也代表这个程序也完了,所以它不会返回至主程序,这就是要创建子进程的原因,子进程用于执行命令,父进程用于返回!

下面是简单shell的代码:

#include <stdio.h>
#include <unistd.h>
//#define SIZE 20
#define MAXLINE 80
char *p;

void setup (char inputBuffer[], char *argv[])
{
    int i, j;
    i = 0;
    for (p = inputBuffer; ;p++)/*一个一个地将输入字符分开*/
	{
		argv[i++] = p;
		while (*p != ' ' && *p != '\0')
			p++;
		if (*p == '\0')
		{
			break;
		}
		*p = '\0';
   	}
    argv[i] = NULL;
    pid_t pid
    pid = fork();/*新建一个子进程*/
    if (pid == 0)/*对于子进程,执行输入的命令*/
    {
     execvp (argv[0], argv);
	 printf ("command not found\n");/*如果execvp执行失败的话,会返回-1,也就是这句话会被执行*/
    }

    else if( pid > 0 )/*对于父进程,等待*/
    {
	 wait(NULL);/*父进程等待子进程执行完*/
    }

     else /*否则的话,就出错了*/
     {
	  printf ("fork error\n");
     }
}

int main()
{
	char inputBuffer[MAXLINE];
	char *argv[MAXLINE / 2 - 1];

	while (1)
	{
		printf ("COMMAND->");
  		gets (inputBuffer);
		/*关于scanf和gets,scanf对于输入的字符遇到空格或回车就结束了,而gets对于输入的空格也接受*/
		setup (inputBuffer, argv);

	}
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: