一个简单的shell实现
什么是内建命令
内建命令是由shell本身提供的命令,而不是通过外部程序(如位于/bin
、/usr/bin
等目录下的可执行文件)来执行的命令。这些命令在shell启动的时候就加载到内存中,执行效率相对较高。
常见的内建命令有:cd
,pwd
,echo
。
什么是当前路径
本质就是进程的工作目录,默认是进程在哪个目录底下执行,它的工作目录就是这个目录。
那这个工作目录可以更改吗?答案是可以的,使用chdir()
函数就可以更改当前进程的工作目录。
在我们自己实现一个简单的shell,执行cd命令的时候,你会发现路径没有变化。那是因为在执行命令的时候,我们是使用fork()出来的子进程来执行的cd,子进程有自己的工作目录(一般和父进程的工作目录相同),当执行cd的时候,更改的是子进程的目录,子进程执行完毕,什么都没了,继续用的是父进程,即shell。
简单的shell实现
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>#define NUM 1024
#define OP_NUM 64char command[NUM];
char *myargv[OP_NUM];
int lastCode = 0;
int lastSig = 0;int main()
{while (1){char *user = getenv("USER");char *host = getenv("HOSTNAME");printf("%s@%s 当前路径#", user, host);fflush(stdout);char *s = fgets(command, sizeof(command) -1, stdin);//获取命令行的输入assert(s != NULL);(void)s;//清除用户按下的回车command[strlen(command) - 1] = 0;//字符串切割myargv[0] = strtok(command, " ");int i = 1;//显示颜色if (myargv[0] != NULL && strcmp(myargv[0], "ls") == 0) {myargv[i++] = (char*)"--color=auto";}//myargv[] 必须以NULL结尾,而strtok函数结束的时候返回NULL//strtok()中的NULL表示从上次结束的位置继续查找下一个子串while (myargv[i++] = strtok(NULL, " ")) {}//不需要创建子进程,让shell自己执行对应的命令if (myargv[0] != NULL && strcmp(myargv[0], "cd") == 0){if (myargv[1] != NULL) chdir(myargv[1]);continue;}if (myargv[0] != NULL && myargv[1] != NULL && strcmp(myargv[0], "echo") == 0){if (strcmp(myargv[1], "$?") == 0) printf("%d, %d\n", lastCode, lastSig);else printf("%s\n", myargv[1]);continue;}//创建子进程pid_t id = fork();assert(id != -1);if (id == 0){//程序替换execvp(myargv[0], myargv);exit(1);}int status = 0;pid_t ret = waitpid(id, &status, 0);assert(ret > 0);(void)ret;lastCode = WEXITSTATUS(status);lastSig = WIFEXITED(status);}
}