2010-09-17 71 views

回答

38

這取決於你想用腳本(或者你想運行其他程序)做什麼。

如果你只是想運行腳本system是最容易做的事情,但它也做一些其他的事情,包括運行一個shell並讓它運行命令(/ bin/sh在大多數* nix下)。

如果要通過其標準輸入提供shell腳本或使用其標準輸出,可以使用popen(和pclose)設置管道。這也使用shell(大多數* nix下的/ bin/sh)來運行該命令。

這兩個都是庫函數,它們在底層做了很多工作,但如果它們不能滿足你的需求(或者你只是想實驗和學習),你還可以直接使用系統調用。這也可以讓你避免讓shell(/ bin/sh)爲你運行你的命令。

感興趣的系統調用是fork,execvewaitpid。您可能需要使用execve(關於它們的列表,請輸入man 3 exec)的庫封裝器之一。您可能還想使用其他等待功能之一(man 2 wait擁有這些功能)。此外,您可能對與fork有關的系統調用clonevfork感興趣。

fork重複當前程序,其中唯一的主要區別是新進程從調用fork返回0。父進程獲取新進程的進程ID(或錯誤)。

execve用新程序替換當前程序(保持相同的進程ID)。

waitpid被父進程用於等待特定的子進程完成。

讓fork和execve步驟分離後,程序可以在創建新過程之前對其進行一些設置(而不會自動搞亂)。這些包括將標準輸入,輸出和標準錯誤更改爲與所使用的父進程不同的文件,更改進程的用戶或組,關閉子進程不需要的文件,更改會話或更改環境變量。

您可能也有興趣pipedup2系統調用。 pipe創建一個管道(同時具有輸入和輸出文件描述符)。dup2將文件描述符複製爲特定的文件描述符(dup類似,但將文件描述符複製到最低可用文件描述符)。

+2

還值得注意的是fork()是相當便宜的,因爲內存是寫入時拷貝,並且一旦程序分叉就不會重複。 – Cercerilla 2010-09-17 15:33:26

+0

我是fork/exec的忠實粉絲 - 它可以讓您避免不確定運行環境的環境。但是你可以直接在shell腳本上使用它嗎?正如你所說,通過使用exec,你「避免讓shell(/ bin/sh)爲你運行你的命令」;難道你不需要exec/bin/sh來運行一個shell腳本嗎? – 2010-09-17 16:33:43

+1

@Tom Anderson:如果shell腳本爲有效用戶設置了執行權限並且有一個合適的shabang第一行列出了有效用戶也有權執行的文件,而且它本身不是某種腳本,那麼內核將會用腳本文件調用shabang行上列出的文件。如果腳本的shabang是'#!/ bin/csh',那麼'/ bin/sh'不會在fork/exec場景中運行。如果它是'#!/ bin/sh',那麼它將在fork/exec場景中運行,但是對於此腳本,使用'system'版本'/ bin/sh'將運行兩次。 – nategoose 2010-09-17 16:43:09

23

您可以使用system

system("/usr/local/bin/foo.sh"); 

同時使用sh -c執行它這將阻止,則返回的狀態代碼。

+3

+1不要忘了包括''(HTTP:// linux.die.net/man/3/system) – pmg 2010-09-17 14:34:06

+1

...假設它有可執行位和shebang行。一般來說,'system(「/ bin/sh /usr/local/bin/foo.sh」);'。是的,這實際上調用了兩次shell。 – 2010-09-17 15:07:29

1

如果您需要更精細的等級控制,您還可以去forkpipeexec路線。這將允許您的應用程序檢索從shell腳本輸出的數據。

15

如果你確定與POSIX,您還可以使用popen()/pclose()

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

int main(void) { 
/* ls -al | grep '^d' */ 
    FILE *pp; 
    pp = popen("ls -al", "r"); 
    if (pp != NULL) { 
    while (1) { 
     char *line; 
     char buf[1000]; 
     line = fgets(buf, sizeof buf, pp); 
     if (line == NULL) break; 
     if (line[0] == 'd') printf("%s", line); /* line includes '\n' */ 
    } 
    pclose(pp); 
    } 
    return 0; 
} 
+0

感謝您使用此示例代碼。 – 2016-12-10 20:20:31

1

我更喜歡fork + execlp作爲doron提到的「更精細」控件。 示例代碼如下所示。

將命令存儲在char數組參數中,並將malloc空間存儲爲結果。

int fd[2]; 
pipe(fd); 
if ((childpid = fork()) == -1){ 
    fprintf(stderr, "FORK failed"); 
    return 1; 
} else if(childpid == 0) { 
    close(1); 
    dup2(fd[1], 1); 
    close(fd[0]); 
    execlp("/bin/sh","/bin/sh","-c",parameters,NULL); 
} 
wait(NULL); 
read(fd[0], result, RESULT_SIZE); 
printf("%s\n",result); 
+0

'close(1);'是不需要的,因爲dup2()在重新分配它之前會自行關閉newfd。 – FedericoCapaldo 2017-06-09 23:11:08

2

一個簡單的方法是.....

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


#define SHELLSCRIPT "\ 
#/bin/bash \n\ 
echo \"hello\" \n\ 
echo \"how are you\" \n\ 
echo \"today\" \n\ 
" 
/*Also you can write using char array without using MACRO*/ 
/*You can do split it with many strings finally concatenate 
    and send to the system(concatenated_string); */ 

int main() 
{ 
    puts("Will execute sh with the following script :"); 
    puts(SHELLSCRIPT); 
    puts("Starting now:"); 
    system(SHELLSCRIPT); //it will run the script inside the c code. 
    return 0; 
} 

說感謝
尤達@http://www.unix.com/programming/216190-putting-bash-script-c-program.html