1. 程式人生 > >Shell實現(三)讀取命令的實現

Shell實現(三)讀取命令的實現

基本思路

  • 讀取命令我採取的讀取整個字串後再進行分段和分析:
    • 首先是parse_token將字串通過分號為分隔,得到每組命令,每組命令當中只包含管道,輸入輸出重定向和單條命令及其引數。
    • 然後是parse_group將每段得到的字串通過管道為分隔,得到只包含引數,輸入輸出重定向和單條命令的更加簡單的命令串
    • 最後是parse_command分析單條指令,得到輸入輸出重定向的檔案流和命令的屬性還有命令的引數。
    • 從記憶體中取出佔位放入命令,然後將命令分組(組內連續)

具體實現:

  • 首先是parse_token
//遍歷字串以";"為分隔得到字串組,用0取代;代表字串結束,實現字串的劃分
void parse_token ( char* buf ) { int n = strlen ( buf ),i,j=0; n--; buf[n] = 0; for ( i = 0 ; i < n ; i++ ) if ( buf[i] == ';'|| i == n-1 ) { if ( buf[i] == ';' ) buf[i] = 0; parse_group ( buf+j ); j = i+1; } }
  • 然後是parse_group,與parse_token思路相似
//以“|”為分隔得到字串組,用0取代|的位置代表字串結束,實現字串的劃分
//mode代表得到的單條指令在組中的位置,只有兩端的不通過管道的傳遞資訊
//1代表中間位置
void parse_group ( char* buf )
{
    int n = strlen ( buf ),i,j=0;
    int x = cnt_cmd;
    for ( i = 0 ; i < n ; i++ )
        if ( buf[i] == '|' || i == n-1 )
        {
            int
mode = 0; if ( buf[i] == '|' ) { buf[i] = 0; mode = 1; } parse_command ( buf+j , mode ); j = i+1; } group[cnt_group].first = x;//對指令進行分組 group[cnt_group].last = cnt_cmd; cnt_group++; }
  • 最後是parse_command
//parse_command分析單條指令
void parse_command ( char* buf , int mode )
{
    int n = strlen ( buf ),i=0,j=0;
    while ( buf[i] ==' '|| buf[i] == '\t' ) i++,j++;//去掉沒有用的空格
    int id = init_cmd ();//從記憶體池中取出一個命令的槽
    if ( mode == 1 ) cmd[id].type |= PIPE;//如果命令位於中間位置,那麼設定為屬性包含PIPE屬性
    char* segment[MAX_ARGS];//儲存劃分段的位置的指標
    int x=0;
    for ( ; i < n ; i++ )
        if ( buf[i] == ' ' || i == n-1 )
        {
            if ( buf[i] == ' ' ) buf[i] = 0;
            segment[x++] = buf+j;
            j = i+1;
            while ( buf[j] == ' ' || buf[j] == '\t' )
                j++,i++;
        }
    //分析指令,查詢檔案的重定向和向引數列表中新增引數
    int temp = 0;
    cmd[id].cmd = segment[0];
    cmd[id].param = malloc(sizeof (char*)*(MAX_ARGS+2) );
    if ( x > 0 )
        cmd[id].param[temp++] = segment[0];
    for ( i = 1; i < x ; i++ )
    {
        int flag = 1;
        if ( strlen(segment[i]) == 1 )
        {
            if ( segment[i][0] == '<' )
            {
               flag = 0;
               cmd[id].input = segment[i+1];
               i++;
            }
            else if ( segment[i][0] == '>' )
            {
               flag = 0;
               cmd[id].output = segment[i+1];
               i++;
            }
        }
        if ( strlen ( segment[i] ) == 2 )
        {
            if ( strcmp ( segment[i] , "<<" ) == 0 )
            {
                flag = 0;
                cmd[id].input = segment[i+1];
                i++;
            }
            else if ( strcmp ( segment[i] , ">>" ) == 0 )
            {
                flag = 0;
                cmd[id].output = segment[i+1];
                i++;
            } 
        }
        if ( flag )
        {
            cmd[id].param[temp++] = segment[i];
        }
    }
}

需要用到的函式庫中的函式

  • string.h裡的一些簡單的字串操作函式
  • char* flag = fgets ( buf , BUFSIZE , stdin);用於讀取一行資料的函式,第一個是快取區間的首地址,第二個為快取區間的規模,第三個為輸入流
  • malloc向堆申請記憶體