1. 程式人生 > >Linux shell命令解析器(一),bash終端

Linux shell命令解析器(一),bash終端

環境:

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; }