2016-04-08 64 views
5

雖然我認爲我掌握瞭如何在C中使用fork(),exec(),wait()pid,但我還沒有找到如何在程序中運行個人程序的方法。如何從終端輸入(linux)運行程序?

這裏是我的代碼:

#include<stdio.h> 
#include<stdlib.h> 
#include<unistd.h> /* for fork() */ 
#include<sys/types.h> /* for pid_t */ 
#include<sys/wait.h> /* fpr wait() */ 

int main(int argc, char* argv[]) 
{ 
    char fileName[255]; 
    pid_t pid; 

    switch (pid = fork()) { 
    case -1: //Did not fork properly 
     perror("fork"); 
     break; 

    case 0: //child 
     execv(fileName[0],fileName); 

     puts("Oh my. If this prints, execv() must have failed"); 
     exit(EXIT_FAILURE); 
     break; 
    default: //parent 
     //Infinite Loop 
     while (1) { 
      printf(" %s > ", argv[0]); 
      scanf("%s", fileName); // gets filename 
      if (fileName[0] == '\0') continue; 
      printf("\n Entered file: %s",fileName); // prints the fileName 
      waitpid(pid,0,0); /* wait for child to exit() */ 
      break; 
     } 
    } 

    return 0; 
} 

我的問題有以下幾點:

  1. 我想帶一個字符串作爲輸入,我想它的範圍限制在255個字符。是char fileName[255]然後scanf("%s", fileName);要走的路?我應該使用getLine()還是其他一些功能?

  2. 假設輸入正確。我如何執行說一個現有的hello世界程序。輸入是否存儲在*argv[]?我發現在不同的程序中,我可以使用

    static char *argv[] = { "echo", "Foo is my name." , NULL }; 
    execv("/bin/echo", argv); 
    

    爲了回聲「Foo是我的名字」。我可以用helloWorld程序做類似的事嗎?

回答

2

你傳遞一個字符的命令名稱,該名稱字符串作爲參數列表的開始 - 彷彿原型execv()int execv(char cmd, char *args)

實際的原型是:int execv(char *cmd, char **args),所以你需要:

char *args[2] = { fileName, 0 }; 

execv(args[0], args); 

我假設你設置fileName爲有意義的價值的地方 - 即不顯示。例如,它可能是"./local_program"。它將被視爲可執行文件的路徑名。

如果你想讀的名字,那麼你可以使用fgets()getline(),但你需要刪除換行符:

if (fgets(fileName, sizeof(fileName), stdin) != 0) 
{ 
    fileName[strcspn(fileName, "\n")] = '\0'; 
    …as before… 
} 

或:

char *fileName = 0; 
size_t length = 0; 
if (getline(&fileName, &length, stdin) != -1) /* Not EOF! */ 
{ 
    fileName[strcspn(fileName, "\n")] = '\0'; 
    …as before… 
} 
free(fileName); 

採用strcspn()避免必須特殊情況下過長的命令行,以使fileName中沒有換行符。請注意,這不會嘗試將輸入行分隔爲空格或類似的任何類型的命令名稱和參數。這是貝實施一個新的水平:

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

int main(void) 
{ 
    char fileName[256]; 
    if (fgets(fileName, sizeof(fileName), stdin) != 0) 
    { 
     fileName[strcspn(fileName, "\n")] = '\0'; 
     char *args[129]; 
     char **argv = args; 
     char *cmd = fileName; 
     const char *whisp = " \t\f\r\b\n"; 
     /* Ugh — strtok()? OK while only handling white space separators */ 
     char *token; 
     while ((token = strtok(cmd, whisp)) != 0) 
     { 
      *argv++ = token; 
      cmd = 0; 
     } 
     *argv = 0; 

     execv(args[0], args); 
     fprintf(stderr, "Oops!\n"); 
    } 
    return 1; 
} 

我並不需要檢查的args陣列的溢出,因爲輸入,減去終止空的256個字符,不能被分割生產超過128個單字符的參數,每一個都與一個單獨的空格字符相鄰。使用strtok()是臨時的創可貼。只要你需要處理真正的shell語法(管道,I/O重定向,帶空格的引用字符串等),strtok()是非常糟糕的工具。 (它 - strtok() - 也是在任何庫函數中使用的錯誤函數。。在Unix或微軟的strtok_s()在Windows上使用POSIX strtok_r()如果你必須使用庫代碼strtok()樣功能)

+1

謝謝你的快速和完整的答案。你無法完全理解的問題的唯一部分是假設我將fileName設置爲一個值。你的意思是初始化嗎?在那種情況下,我沒有。我需要嗎?在我腦海中當程序運行時,它會提示用戶和用戶輸入類似「./helloWorld」或「/bin/./helloWorld」的內容。這將是fileName的值。 –

+1

該名稱的輸入是我的意思是'將'fileName'設置爲一個值'。正如所寫的,您使用未初始化的字符串作爲命令,這不太可能奏效。只要你將'fileName'設置爲某種適當的東西,你應該沒問題。 '。/ helloWorld'和'/ bin /./ helloWorld'都可以工作,不需要'./'('execv()'不受'$ PATH'的影響,如果只指定'helloWorld',它將被視爲與'。/ helloWorld'相同)。 '/ bin /./ helloWorld'是iffy; '/./'可能只是'/',你不應該把軟件放在'/ bin'中。 –

0

既然這樣,你需要修復你的代碼中的編譯錯誤:

g++ -std=c++11 -g -Wall -Wextra -Wwrite-strings  36501711.cpp -o 36501711 
36501711.cpp: In function ‘int main(int, char**)’: 
36501711.cpp:18:25: error: invalid conversion from ‘char’ to ‘const char*’ [-fpermissive] 
     execv(fileName[0],fileName); 
         ^
36501711.cpp:18:35: error: cannot convert ‘char*’ to ‘char* const*’ for argument ‘2’ to ‘int execv(const char*, char* const*)’ 
     execv(fileName[0],fileName); 
           ^
36501711.cpp: At global scope: 
36501711.cpp:7:5: warning: unused parameter ‘argc’ [-Wunused-parameter] 
int main(int argc, char* argv[]) 
    ^

警告(關於未使用的argc)是無害的,但錯誤是真實的,需要修復。

您需要fileName你叉初始化,否則孩子不會有任何有效的數據有:

#include<stdio.h> 
#include<stdlib.h> 
#include<unistd.h> /* for fork() */ 
#include<sys/types.h> /* for pid_t */ 
#include<sys/wait.h> /* fpr wait() */ 

int main(int argc, char* argv[]) 
{ 
    char fileName[255]; 
    pid_t pid; 

    //Infinite Loop 
    while (1) { 
     printf(" %s > ", argv[0]); 
     scanf("%s", fileName); 
     if (fileName[0] == '\0') 
      break; 
     printf("\n Entered file: %s\n", fileName); 

     pid = fork(); 
     switch (pid) { 
     case -1: //Did not fork properly 
      perror("fork"); 
      break; 

     case 0: //child 
      execl(fileName, fileName, 0); 
      perror("exec"); 
      exit(EXIT_FAILURE); 
      break; 

     default: //parent 
      waitpid(pid,0,0); /* wait for child to exit() */ 
      break; 
     } 
    } 

    return EXIT_SUCCESS; 
}