Linux shell命令解析器(一),bash終端
阿新 • • 發佈:2018-12-19
環境:
Ubuntu14-4 核心 4.4.0-135
vim編輯器 7.4
gcc 4.8.4
1.1 知識點
- Shell 的基本概念
- 程序控制相關的系統呼叫的使用(如 fork,exec函式族)
整理框架:
1.命令直譯器首先是一個死迴圈。
2.列印一個命令提示符。
3.取得命令列輸入放在數組裡面,要求命令帶引數。可以getc()、fgets()、scanf()等。
4.如果用fgets()的話,取得的字串包括最後輸入的換行符,故要去掉命令字串末尾的“/n”,變成“/0”。
5.用字串切割函式將得到的命令列以空格切割儲存在字串陣列中。
6.建立一個子程序,呼叫exec執行命令,將切割得到的命令以及引數傳入。
7.父程序呼叫waitpid()等待子程序的退出,然後進入下一次迴圈。
bash終端部分:
#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<string.h> #include<assert.h> #include<sys/stat.h> #include<sys/types.h> #include<sys/utsname.h> #include<pwd.h> #define STRLEN 128 //命令列提示符 void PrintfFlag() { struct passwd *pw=getpwuid(getuid());//得到當前使用者的名稱的結構體指標pw assert(pw!=NULL); struct utsname un;//得到主機標識 uname(&un); // assert(uname!=NULL); char shortname[STRLEN]={0}; memmove(shortname,un.nodename,9); char path[STRLEN]={0};//得到當前工作路徑 getcwd(path,STRLEN-1); char *p=path; if(strcmp(path,"/")==0) { p="/"; } // else if(strcmp(p,getenv("HOME"))==0) else if(strcmp(p,pw->pw_dir)==0) { p="~"; } else { p=path+strlen(path); while(*p--!='/'); p+=2; } char flag='$';//得到當前使用者狀態 if(getuid()==0) { flag='#'; } printf("[%
[email protected]%s %s]%c ",pw->pw_name,shortname,p,flag); } void CutCmd(char *cmd,char *argv[]) { int count=0; char *p=strtok(cmd," "); //以空格分割cmd,將得到的字串儲存在argv字串陣列中 while(p!=NULL) { argv[count++]=p; if(count==STRLEN) { break; } p=strtok(NULL," "); } } void CdCmd(char *path) { static char PrePath[STRLEN]={0}; //靜態區儲存上一次目錄 struct passwd*pw=NULL; if(strcmp(path,"~")==0) { pw=getpwuid(getuid()); assert(pw!=NULL); path=pw->pw_dir; } else if(strcmp(path,"-")==0) { if(strlen(PrePath)==0) { printf("OLDPWD not set\n"); return ; } path=PrePath; } char NowPath[STRLEN]={0}; getcwd(NowPath,STRLEN-1); //獲得當前工作目錄 if(-1==chdir(path)) //工作目錄轉移 { printf("bash: cd: %s: No such file or director\n",path); } else { strcpy(PrePath,NowPath); } } int main() { while(1) { PrintfFlag(); char cmd[STRLEN] = {0}; fgets(cmd,STRLEN,stdin);// 輸入命令 cmd[strlen(cmd) - 1] = 0; if(strlen(cmd) == 0) { continue; } if(strcmp(cmd,"exit") == 0) { exit(0); } char *argv[STRLEN] = {0}; CutCmd(cmd,argv); //比如:argv[0]="ls",argv[1]="-al",argv[2]=getcwd(); if(strcmp(argv[0],"cd") == 0) { CdCmd(argv[1]); continue; } pid_t pid=fork(); assert(pid != -1); if(pid == 0) { char path[STRLEN] = {"/home/zhao/Desktop/shell/bin/"}; if(strstr(argv[0],"/") != NULL)//防止帶路經命令引起路徑錯誤 { memset(path,0,STRLEN); } strcat(path,argv[0]); execv(path,argv); printf("bash: %s: command not found\n",argv[0]); exit(0); //當exec函式呼叫失敗時,子程序能夠安全推出 } else { wait(NULL); } } return 0; }