在前文中我们根据之前所学习的相关知识编写了一个简单的bash程序,本文中我们来继续将这个程序进行一些简单的优化。
首先就是我们自己编写的shell并没有颜色,而系统自带的是有颜色的,这通过下图可以看出要添加颜色需要给我们的指令添加红框中的语句。
// 通过在字符串分割之后,匹配ls指令然后在其末尾添加,与生成颜色对应的指令 if (strcmp(argv[0], "ls") == 0) { int pos = 0; while (argv[pos] != NULL) pos++; argv[pos++] = (char*)"--color=auto"; argv[pos] = NULL; }
如此之后就可以发现可以正常的打印带有颜色
然后是我们在使用pwd指令之后,我们的路径无法切换。
因为pwd指令是由子进程执行的,执行成功更改的也只是子进程的路径,与父进程无关,所以我们要然父进程自己执行该命令,这种命令称之为内建命令。这里我们可以使用chdir指令来修改当前的路径。
// cd .. cd / 然bash自己执行的命令,我们称之为内建命令/内置命令 if (strcmp(argv[0], "cd") == 0) { // 说到底,cd命令,重要的表现就如同bash自己调用了对应的函数 if (argv[1] != NULL) chdir(argv[1]); continue; }
还有就是export指令有一些问题,从之前的学习中也可以得知export也应该是一个内建命令,很正常我们仿照上面的思路进行修改:但是会遇到一些问题:
// 我们自己编写的打印环境变量的方法
void showEnv()
{
extern char** environ;
for (int i = 0; environ[i]; ++i)
{
printf("%d:%s\n", i, environ[i]);
}
}
// 紧接着cd指令的补充
// 原因:环境变量在export的时候是放在argv[1]中的,而argv字符串是一个变化的字符串,argv字符串指向的是commangstr中的内容 ,commandstr中的内容在不断地变化,未来在命令行获取的时候不断地被解析,字符串的起始地址会不断地被覆盖掉,因此环境变量一直在变化
else if (strcmp(argv[0], "export") == 0)
{
// if (argv[1] != NULL) putenv(argv[1]);
if (argv[1] != NULL)
{
strcpy(myenv[env_index], argv[1]);
putenv(myenv[env_index++]);
}
continue;
}
else if (strcmp(argv[0], "env") == 0)
{
showEnv();
continue;
}
// fork后的内容
if(id == 0)
{
//child
// execvpe(argv[0], argv, environ); // 无论我们是否手动传递环境,系统自己都会给子进程传递父进程的环境变量
execvp(argv[0], argv);
exit(1);
}
再实现一下echo$?和echo$环境变量的指令
else if (strcmp(argv[0], "echo") == 0)
{
// echo $PATH
const char* target_env = NULL;
if (argv[1][0] == '$') // argvp中存放的是指针,argv[]获取的是指针数组的每一个指针,argv[][]就可以获取我们想要的字符
{
// 对echo后面的字符进行判断是$?还是$环境变量
if (argv[1][1] == '?')
{
printf("%d\n",last_exit);
}
else
{
target_env = getenv(argv[1] + 1);
}
if (target_env != NULL) printf("%s = %s\n", argv[1] + 1, target_env);
}
continue;
}