2014-01-26 2 views
2

Это один из шагов набора упражнений, которые я делаю. Программа, которую я пишу, должна принимать более двух аргументов. Использование первого аргумента еще не реализовано. Остальные аргументы представляют собой список каталогов.Кошка с вилкой трубы execvp и dup2

На этом этапе мне нужно создать экземпляр cat для каждого каталога, заданного в аргументах, взять содержимое всех файлов каждого каталога, используя cat, и распечатать содержимое. Я должен уметь обрабатывать пути, такие как/home/directory и/home/directory/both (с последним/или без)

В настоящее время я пытаюсь запустить cat с аргументом/home/directory/* так что он будет читать все файлы в данном каталоге и возвращать их содержимое. Это мой код:

#include "Step1.h" 

int main(int argc,char* argv[]) 
{ 
    if(argc < 3) 
    { 
     printf("Usage: ./Step1 <exclusions file> <folder1> <folder2> <folder3> ...\n"); 
     return -1; 
    } 

    int i; 
    for(i=2; i<argc; i++) 
    { 
     int catpipe[2]; 
     if(pipe(catpipe)) 
     { 
      printf("Error in pipe\n"); 
      return -1; 
     } 
     pid_t pid = fork(); 
     if(pid < 0) 
     { 
      printf("Error in fork\n"); 
      return -1; 
     } 
     if(!pid) 
     { 
      dup2(catpipe[1],1); // cat pipe is used to get the output of cat program into this program. 
      close(catpipe[1]); 
      close(catpipe[0]); 
      char* args[3]; 
      args[0] = "/bin/cat"; 
      int length = strlen(argv[i]); 
      char* path; 
      if(argv[i][length - 1] != '/') // the path given does not have the ending/
      { 
       path = malloc(length + 3); 
       strcpy(path,argv[i]); 
       path[length] = '/';  //append/at the end 
       path[length+1] = '*'; // append * at the end 
       path[length+2] = '\0'; 
      } 
      else 
      { 
       path = malloc(length + 2); // the path contains the ending/
       strcpy(path,argv[i]); 
       path[length] = '*';  // append * at the end 
       path[length+1] = '\0'; 
      }     
      args[1] = path; 
      args[2] = NULL; 
      printf("%s\n",path); 
      execvp("/bin/cat",args); 
     } 
     close(catpipe[1]); 
     char buffer[200]; 
     int total = read(catpipe[0],buffer,200); // read the output of cat program and print it. 
     buffer[total]='\0'; 
     printf("The buffer contains: %s\n",buffer); 
    } 
    return 0; 
} 

Я побежал этот код следующим образом:

[email protected]:~/project$ ./Step1 exclusions ./testdirectory1 ./testdirectory2/ 

и результат я получил это:

/bin/cat: ./testdirectory1/*: No such file or directory 
The buffer contains: 
The buffer contains: ./testdirectory2/* 

[email protected]:~/project$ /bin/cat: ./testdirectory2/*: No such file or directory 

[email protected]:~/project$ 

но когда я делаю:

[email protected]:~/project$ /bin/cat ./testdirectory1/* 

Результат:

Testline 1 of testfile1 in testdirectory1 
Test line 1 of testfile1 in testdirectory1 
Testline 1 of testfile2 in testdirectory1 
Testline 1 of testfile3 in testdirectory1 

Пожалуйста, помогите мне получить этот результат с моей программой.

Заранее спасибо

+0

это потому, что при тестировании в оболочке, то '*' в ваших рассуждениях расширяется оболочки, в то время как, когда вы делаете вилку, то '*' интерпретируется как, просто файл с именем '*' – zmo

+0

@zmo Разве не обойти это? – HZero

+0

см. Мой ответ ;-) – zmo

ответ

0

Поэтому в основном то, что вы получите неправильно в вашем коде, что вы предполагаете, что если вы даете /directory/* в качестве аргумента cat, cat расширит его как «много файлов», в то время как cat понимает, что хотите открыть файл под названием *.

Простым способом расширения * было бы вызвать кошку через оболочку, которая будет делать расширение от * до «многих файлов».

Для достижения так, вы можете заменить ваш execvp() с system(…) вызова, который в основном execl("sh", "sh", "-c", …, NULL), где ... это ваша команда (например, вы можете просто позвонить "/bin/sh", "-c", "/bin/cat", "/directory/*") и там * должен быть расширен за счет оболочки.

Или вы может работать с вашим собственным рекурсивным алгоритмом хоста каталогов, например that one.

+0

Спасибо. Мне было поручено использовать glob() или wordexp(). Есть ли недостаток в этом? – HZero

0

Я думаю, что я понял ответ на свой вопрос. Я отправляю это в надежде, что кто-то, как я, найдет его полезным в один прекрасный день. «Не очень хорошо в C еще. Так что если этот ответ неправильный или если есть какая-то ошибка/слабость в этом, не стесняйтесь исправить это.

Ключом для ответа является использование функции wordexp(). Его можно использовать для расширения данного пути: тильда, регулярные выражения, переменные и все. Так вот мой ответ:

#include "Step1.h" 

int main(int argc,char* argv[]) 
{ 
    if(argc < 3) 
    { 
     printf("Usage: ./Step1 <exclusions file> <folder1> <folder2> <folder3> ...\n"); 
     return -1; 
    } 

    int i; 
    for(i=2; i<argc; i++) 
    { 
     int catpipe[2]; 
     if(pipe(catpipe)) 
     { 
      printf("Error in pipe\n"); 
      return -1; 
     } 
     pid_t pid = fork(); 
     if(pid < 0) 
     { 
      printf("Error in fork\n"); 
      return -1; 
     } 
     if(!pid) 
     { 
      dup2(catpipe[1],1); // cat pipe is used to get the output of cat program into this program. 
      close(catpipe[1]); 
      close(catpipe[0]); 

      int length = strlen(argv[i]); 
      char* path; 
      if(argv[i][length - 1] != '/') // the path given does not have the ending/
      { 
       path = malloc(length + 3); 
       strcpy(path,argv[i]); 
       path[length] = '/';  //append/at the end 
       path[length+1] = '*'; // append * at the end 
       path[length+2] = '\0'; 
      } 
      else 
      { 
       path = malloc(length + 2); // the path contains the ending/
       strcpy(path,argv[i]); 
       path[length] = '*';  // append * at the end 
       path[length+1] = '\0'; 
      }    

     wordexp_t p; 
     char **w; 
      wordexp(path, &p, 0); 
     char** args = malloc((p.we_wordc + 2) * sizeof(char*)); 
      args[0] = "/bin/cat"; 
     w = p.we_wordv; 
     int j; 
     for (j = 0; j < p.we_wordc; j++) 
     args[j+1] = w[j];     
      args[p.we_wordc + 1] = NULL; 

      execvp("/bin/cat",args); 
     } 
     close(catpipe[1]); 
     char buffer[1024]; 
     int total = read(catpipe[0],buffer,1024); // read the output of cat program and print it. 
     buffer[total]='\0'; 
     printf("The buffer contains: %s\n",buffer); 
    } 
    return 0; 
} 
+0

Если вы полны решимости сделать расширение метасимволов оболочки, то вы правильно занялись этой работой. Более простая альтернатива - использовать оболочку для расширения метасимвола оболочки; вы вызываете 'sh -c" cat $ directory/* "', понимая, что двойные кавычки фактически не нужны, и используя аргумент, который вы указали вместо '$ directory'. В общем, вам понадобится цикл для чтения ответов, а не один вызов 'read()'. –

Смежные вопросы