2015-04-02 31 views
-2

我想執行多個命令,如./shell ls > test.txt;ls > test1.txt;ls > test2.txt;,它應該在提到的文件中打印輸出3次。但是,不知何故,我的代碼只打印一次。用';'分隔C中的嵌套循環strtok_r問題和''

我已經用';'分隔char緩衝區使用strtok_r。

另外,我有一個尋找其他的例子是類似我的問題: Nested strtok function problem in C

這是我的代碼

void call_system(char *argv[],int argc) 
{ 
    struct sigaction sa; 
    sigemptyset(&sa.sa_mask); 
    sa.sa_flags = 0; 
    sa.sa_handler = child_handler; 
    sigaction(SIGCHLD, &sa, NULL); 

    int pid; 
    int background; 
    /*two process are created*/ 
    pid=fork(); 
    background = 0; 

    if(pid<0) 
    { 
     fprintf(stderr,"unsuccessful fork /n"); 
     exit(EXIT_SUCCESS); 
    } 
    else if(pid==0) 
    { 
     chdir("h/Ravi Griffith/Sem 1-2015/SP/Assignment1/Assignment1"); 

     char *bname; 
     char *path2 = strdup(*argv); 
     bname = basename(path2); 

     execvp(bname, argv); 
    } 
    else if(pid>0) 
    { 
     /*it will wait untill the child process doesn't finish*/ 
     child_handler(pid); 
     exit(EXIT_SUCCESS); 
    } 
} 

int main(int argc,char *argv[]) 
{ 
    if(argc>1) 
    { 
    /*it will check whether a user has entered exit then the code will be executed successfully.*/ 
     if(strcmp(argv[1], "exit")==0) 
     { 
     exit(EXIT_SUCCESS); 
     } 
    } 
    else 
    { 
     printf("Enter Shell Command -- "); 
     char buffer[80]; 

     fgets(buffer, sizeof(buffer), stdin); 
     //it will replace the newline character with null 
     buffer[strlen(buffer) - 1] = '\0'; 
     char *end_str; 
     char* token= strtok_r(buffer, ";", &end_str); 

     /* string will be split in individual argument array */ 
     while(token != NULL) 
     { 
      int i; 
      char *endtoken; 
      printf("a = %s\n", token); 
      char *array[strlen(buffer)]; 
      i = 0; 
      char *token2 = strtok_r(token," ", &endtoken); 
      while (token2 != NULL) 
      { 
       array[i++] = token2; 
       token2 = strtok_r(NULL, " ", &endtoken); 
      } 

      if(sizeof(array)>16) 
      { 
       char *arrow=array[strlen(buffer)-1]; 
       char *filename; 
       filename=array[strlen(buffer)]; 
       /*printf("%s",arrow); 
       printf("%s",filename);*/ 
       if(strcmp(arrow, ">") == 0) 
       { 
        freopen(filename, "w", stdout); 
       } 
       else if(strcmp(arrow, "<") == 0) 
       { 
        freopen(filename, "rb", stdin); 
       } 
      } 

      splittoarray(buffer,argv); 

      call_system(argv,argc); 
      token = strtok_r(NULL, ";",&end_str); 
     } 
    } 
} 
+0

您可能需要使用'strsep'相反,因爲你似乎wa nt嵌套調用'strtok','strtok'不能這樣工作。 – user3386109 2015-04-02 02:52:40

+0

@ user3386109你能舉個例子嗎? – 2015-04-02 03:05:25

+0

@Jonathan Leffler,任何想法,爲什麼它不工作 – 2015-04-02 03:42:58

回答

1

鑑於嵌套的命令行分割成單個參數的討論時尚與strtok_r,我把下面的例子放在一起,以概述它的應用到你的問題。 (我省略了,您的具體代碼與分裂無關,並且我根據需要進行了更改)。原始分割代碼的最大問題是,在聲明靈活的指針數組以保存指向由strtok_r返回的令牌的指針之後,只需將指針strtok_r的返回值分配給指針數組,而不分配內存並將指向的字符串副本通過token/token2

雖然strtok_r將返回指向每個令牌的指針,但token指向的內存位置可以在下次調用strtok_r時更改。因此,爲了保留令牌供以後使用,在下次調用strtok_r之前,需要製作token/token2指向的字符串的副本。其他

一個問題需要注意的是,隨着;分裂,當你去各個命令拆分成其ARGS後,你不能簡單地傳遞到自己的token令牌陣列的字符串(strtok_r修改原始)。您必須複製token陣列中的每個字符串,並將副本指針傳遞到strtok_r。這樣,您將開始地址保留爲每個分配的token字符串,以防止您在稍後將指針傳遞到free時阻止來自SegFault的程序。

下面是一個簡單的例子:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

int main(int argc,char *argv[]) 
{ 
    if(argc > 1 && strcmp (argv[1], "exit")==0) { 
     exit(EXIT_SUCCESS); 
    } 

    printf("Enter Shell Command -- "); 
    char buffer[80]; 

    fgets(buffer, sizeof(buffer), stdin); 

    /* replace the newline character with null */ 
    buffer[strlen(buffer) - 1] = '\0'; 

    char *cmdarray[strlen (buffer)]; 
    size_t cmdidx = 0; 
    size_t n = 0; 
    char *end_str = NULL; 
    char* token= strtok_r(buffer, ";", &end_str); 

    /* initialize command string array */ 
    for (n = 0 ; n < strlen (buffer); n++) 
     cmdarray[n] = NULL; 

    /* split into individual command string */ 
    while (token) 
    { 
     cmdarray[cmdidx++] = strdup (token); 
     token = strtok_r (NULL, ";", &end_str); 
    } 

    /* loop to process command strings into args */ 
    for (n = 0; n < cmdidx; n++) 
    { 
     size_t i = 0; 
     size_t cmdsz = strlen (cmdarray[n]); 
     size_t arridx = 0; 
     char *token2 = NULL; 
     char *endtoken = NULL; 
     char *array[cmdsz]; 
     char *cmdcopy = strdup (cmdarray[n]); 
     char *sp = cmdcopy; 

     /* initialize argument array */ 
     for (i = 0; i < cmdsz; i++) 
      array[i] = NULL; 

     /* split each command string into argument array */ 
     for (token2 = strtok_r (sp, " ", &endtoken); token2; token2 = strtok_r (NULL, " ", &endtoken)) 
      array[arridx++] = strdup (token2); 

     /* main processing of commands and args here 
     * (print example of all values tokenized) 
     */ 
     printf ("\ncmdarray[%zu] : %s\n", n, cmdarray[n]); 
     for (i = 0; i < arridx; i++) 
      printf (" array[%zu] : %s\n", i, array[i]); 

     /* free memory allocated to array */ 
     for (i = 0; i < arridx; i++) 
      if (array[i]) 
       free (array[i]); 

     /* free copy of command used to tokenize arguments */ 
     if (cmdcopy) 
      free (cmdcopy); 
    } 

    /* free command memory */ 
    n = 0; 
    while (cmdarray[n]) free (cmdarray[n++]); 

    return 0; 
} 

嵌套命令拆分的實例

$ ./bin/strtok_r_nested 
Enter Shell Command -- ./shell ls > test.txt;ls > test1.txt;ls > test2.txt 

cmdarray[0] : ./shell ls > test.txt 
    array[0] : ./shell 
    array[1] : ls 
    array[2] : > 
    array[3] : test.txt 

cmdarray[1] : ls > test1.txt 
    array[0] : ls 
    array[1] : > 
    array[2] : test1.txt 

cmdarray[2] : ls > test2.txt 
    array[0] : ls 
    array[1] : > 
    array[2] : test2.txt 

確認無泄漏

$ valgrind ./bin/strtok_r_nested 
==19622== Memcheck, a memory error detector 
==19622== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al. 
==19622== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info 
==19622== Command: ./bin/strtok_r_nested 
==19622== 
Enter Shell Command -- ./shell ls > test.txt;ls > test1.txt;ls > test2.txt 
    <snip> 

==19622== 
==19622== HEAP SUMMARY: 
==19622==  in use at exit: 0 bytes in 0 blocks 
==19622== total heap usage: 16 allocs, 16 frees, 156 bytes allocated 
==19622== 
==19622== All heap blocks were freed -- no leaks are possible 
==19622== 
==19622== For counts of detected and suppressed errors, rerun with: -v 
==19622== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)