2015-04-03 52 views
0

如果沒有參數,那麼我的程序應該做printenv | sort | less,我已經實現了這個功能。如果main有參數,那麼程序應該做printenv | grep <parameter list> | sort | less,我的問題是調試不起作用。我可以在我的代碼中嘗試聲明printf,它不會執行任何操作。爲什麼?爲什麼我的要求的後半部分不起作用?該計劃有什麼問題?爲什麼我的緩衝區不連接?

預計產量爲printenv | grep <parameter list> | sort | less。例如,我想查詢環境變量,以便執行a.out JOBS COMPIZ UPSTART應該與printenv | grep -e 'JOBS\|COMPIZ\|UPSTART' | sort | less相同。

相反,當試圖分叉命令鏈時,我會得到意想不到的輸出。問題的

#include <sys/types.h> /* definierar bland annat typen pid_t */ 
#include <errno.h> /* definierar felkontrollvariabeln errno */ 
#include <stdio.h> /* definierar stderr, dit felmeddelanden skrivs */ 
#include <stdlib.h> /* definierar bland annat exit() */ 
#include <unistd.h> /* definierar bland annat fork() */ 

struct command 
{ 
    const char **argv; 
}; 

int 
spawn_proc (int in, int out, struct command *cmd) 
{ 
    pid_t pid; 

    if ((pid = fork()) == 0) 
    { 
     if (in != 0) 
     { 
      dup2 (in, 0); 
      close (in); 
     } 

     if (out != 1) 
     { 
      dup2 (out, 1); 
      close (out); 
     } 

     return execvp (cmd->argv [0], (char * const *)cmd->argv); 
    } 

    return pid; 
} 

int 
fork_pipes (int n, struct command *cmd) 
{ 
    int i; 
    pid_t pid; 
    int in, fd [2]; 

    /* The first process should get its input from the original file descriptor 0. */ 
    in = 0; 

    /* Note the loop bound, we spawn here all, but the last stage of the pipeline. */ 
    for (i = 0; i < n - 1; ++i) 
    { 
     pipe (fd); 

     /* f [1] is the write end of the pipe, we carry `in` from the prev iteration. */ 
     spawn_proc (in, fd [1], cmd + i); 

     /* No need for the write and of the pipe, the child will write here. */ 
     close (fd [1]); 

     /* Keep the read end of the pipe, the next child will read from there. */ 
     in = fd [0]; 
    } 

    /* Last stage of the pipeline - set stdin be the read end of the previous pipe 
     and output to the original file descriptor 1. */ 
    if (in != 0) 
     dup2 (in, 0); 

    /* Execute the last stage with the current process. */ 
    return execvp (cmd [i].argv [0], (char * const *)cmd [i].argv); 
} 

int 
main (int argc, char ** argv) 
{ 
    printf("in main..."); 
    int i; 

    if (argc == 1) { 
     const char *printenv[] = { "printenv", 0}; 
     const char *sort[] = { "sort", 0 }; 
     const char *less[] = { "less", 0 }; 

     struct command cmd [] = { {printenv}, {sort}, {less} }; 
     return fork_pipes (3, cmd); 
    } 
    if (argc > 1) { 
     char *tmp = argv[1]; 
     for(i=1; i<argc-1; i++) 
     { 
      sprintf(tmp, "%s%s%s", tmp, "|", argv[i]); 
     } 
     const char *printenv[] = { "printenv", 0}; 
     const char *grep[] = { "grep", "-E", tmp, NULL}; 
     const char *sort[] = { "sort", 0 }; 
     const char *less[] = { "less", 0 }; 

     struct command cmd [] = { {printenv}, {grep}, {sort}, {less} }; 
     return fork_pipes (4, cmd); 
    } 




} 
+1

請將您的問題標題改爲更有意義的內容。 「爲什麼我的程序不能正常工作?」完全沒有跡象表明您要問什麼問題或您遇到什麼問題。問題標題應該包含當他們在搜索結果中看到它時對本網站的未來讀者有用的信息。謝謝。 – 2015-04-03 23:55:12

回答

2

部分是你寫寫入只讀存儲器段argv[1](由於tmp = argv[1]語句)。由於你的寫作超出argv[1]的規模,這更加嚴重。相反,您應該將字符串連接到足夠大小的新可寫緩衝區。

要連接串入tmp變量,你可以使用類似下面的代碼:

// Compute required buffer length 
    int len = 1; // adds 1 to the length to account for the \0 terminating char 
    for(i=1; i<argc; i++) 
    { 
     len += strlen(argv[i]) + 2; // +2 accounts for length of "\\|" 
    } 

    // Allocate buffer 
    tmp = (char*) malloc(len); 
    tmp[0] = '\0'; 
    // Concatenate argument into buffer 
    int pos = 0; 
    for(i=1; i<argc; i++) 
    { 
     pos += sprintf(tmp+pos, "%s%s", (i==1?"":"|"), argv[i]); 
    } 

    printf("tmp:%s", tmp); 
    fflush(stdout); // force string to be printed 

    ... 
    free(tmp); 

至於爲什麼輸出沒有出現,這很可能是由於這樣的事實:printf是線緩衝的。換句話說,直到行尾(\n)必須被打印或者fflush明確強制緩衝區被打印到控制檯時,它通常不會被打印。

注意:不要忘了free()變量tmp一旦你完成它。

+1

@NiklasRosencrantz我已經調整了生成的字符串,以便更符合您想要做的事情。 – SleuthEye 2015-04-03 23:59:23

+0

謝謝。現在我只需要知道如何將參數逐字發送到grep,因爲我的舊通話不再有效。我想我應該使用一些其他的指令,因爲我們不再保留'|'。 – 2015-04-04 00:14:09

+1

什麼樣的論點,你打算傳遞給grep?順便說一句,你需要生成一個字符串數組,如果你希望當你用'execvp'調用grep時將參數作爲分隔參數傳遞(就像你對'grep [] = {「grep」,「-E」,tmp ,NULL};') – SleuthEye 2015-04-04 00:31:50

相關問題