高端网站制作公,响应式网站制作软件,php企业中英文网站源码,建设工程质量管理条例网站文章目录 1.框架2.命令行3.获取用户命令字符串4.命令行字符串分割5.执行命令和内建命令6.完整代码#xff1a; 1.框架
我们知道shell是一直存在的#xff0c;所以首先我们第一步就是要搭建一个框架#xff0c;使其一直存在。 那么也很简单#xff0c;一个while循环就可以完… 文章目录 1.框架2.命令行3.获取用户命令字符串4.命令行字符串分割5.执行命令和内建命令6.完整代码 1.框架
我们知道shell是一直存在的所以首先我们第一步就是要搭建一个框架使其一直存在。 那么也很简单一个while循环就可以完成。
2.命令行
我们的shell最前面都是有一个命令行的 。如下图
那么命令行我们应该怎么获取呢我们可以从环境变量中获取env查看环境变量。 getenv函数就可以帮我们获取环境变量可以获取用户名、地址等等 getenv获取成功就会取到那个对象如果获取失败就会返回空 然后我们需要把上面获取到的三个字符拼接在一起这时候就需要用到snprintf函数了 到这里第一步就结束了
3.获取用户命令字符串
这一步我们需要获取命令字符串因为有空格。我们无法使用scanf。这里使用fgets
4.命令行字符串分割 分割思路 具体分割我们可以使用strtok函数 但是这里有个需要注意的地方strtok的第二参数需要是一个字符串
5.执行命令和内建命令 内建命令
6.完整代码
以上就是编写shell的大致思路了上面的shell为了和系统本身的shell做区分所以前的路径都是绝对路径一长串。 myshell.c:
#include stdio.h
#include stdlib.h
#include string.h
#include errno.h
#include unistd.h
#include sys/types.h
#include sys/wait.h#define SIZE 512
#define ZERO \0
#define SEP
#define NUM 32// 为了方便我就直接定义了
char cwd[SIZE*2];
char *gArgv[NUM];
int lastcode 0;void Die()
{exit(1);
}//获取家目录
const char *GetHome()
{const char *home getenv(HOME);if(home NULL) return /;return home;
}//获取用户名
const char *GetUserName()
{const char *name getenv(USER);if(name NULL) return None;return name;
}
//获取主机名
const char *GetHostName()
{const char *hostname getenv(HOSTNAME);if(hostname NULL) return None;return hostname;
}
//获取路径
const char *GetCwd()
{const char *cwd getenv(PWD);if(cwd NULL) return None;return cwd;
}int GetUserCommand(char command[], size_t n)
{char *s fgets(command, n, stdin);if(s NULL) return -1;command[strlen(command)-1] ZERO;return strlen(command);
}void MakeCommandLineAndPrint()
{char line[SIZE];const char *username GetUserName();const char *hostname GetHostName();const char *cwd GetCwd();snprintf(line, sizeof(line), [%s%s %s] , username, hostname, cwd);printf(%s, line);fflush(stdout);
}void SplitCommand(char command[], size_t n)
{(void)n;// ls -a -l -n - ls -a -l -ngArgv[0] strtok(command, SEP);int index 1;while((gArgv[index] strtok(NULL, SEP))); // done, 故意写成,表示先赋值在判断.因为分割之后如果无法分割strtok会返回NULL刚好让gArgv最后一个元素是NULL, 并且while判断结束
}void ExecuteCommand()
{pid_t id fork();if(id 0) Die();else if(id 0){// childexecvp(gArgv[0], gArgv);exit(errno);}else{// fahterint status 0;pid_t rid waitpid(id, status, 0);if(rid 0){lastcode WEXITSTATUS(status);if(lastcode ! 0) printf(%s:%s:%d\n, gArgv[0], strerror(lastcode), lastcode);}}
}void Cd()
{const char *path gArgv[1];if(path NULL) path GetHome();// path 一定存在chdir(path);// 刷新环境变量char temp[SIZE*2];getcwd(temp, sizeof(temp));snprintf(cwd, sizeof(cwd), PWD%s, temp);putenv(cwd); // OK
}int CheckBuildin()
{int yes 0;const char *enter_cmd gArgv[0];if(strcmp(enter_cmd, cd) 0){yes 1;Cd();}else if(strcmp(enter_cmd, echo) 0 strcmp(gArgv[1], $?) 0){yes 1;printf(%d\n, lastcode);lastcode 0;}return yes;
}int main()
{//首先自己写的shell需要一直存在所以设置一个while循环
int quite0;
while(!quite)
{// 1. 我们需要自己输出一个命令行MakeCommandLineAndPrint();// 2. 获取用户命令字符串char usercommand[SIZE];int n GetUserCommand(usercommand, sizeof(usercommand));if(n 0) return 1;// 3. 命令行字符串分割. SplitCommand(usercommand, sizeof(usercommand));// 4. 检测命令是否是内建命令n CheckBuildin();if(n) continue;
// 5. 执行命令ExecuteCommand();}return 0;
}