2010-09-06 70 views
4

我想知道如何從我的C代碼使用execl(或類似)來執行Python(或Lua等)腳本?如何使用EXECL從C代碼執行Python腳本?

下面是一些「父母/孩子」代碼,顯示了我如何使用PIPES向孩子發送數據流。代碼可能不完美,但你明白了。注意execl底部:

#include <sys/types.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <unistd.h> 

#define STDIN_FILENO 0  /* Standard input. */ 
#define STDOUT_FILENO 1  /* Standard output. */ 
#define STDERR_FILENO 2  /* Standard error output. */ 
#define MAXLINE 4096 

int main(void){ 
int n, parent_child_pipe[2], child_parent_pipe[2]; 
pid_t pid; 
char line[MAXLINE]; 

if (pipe(parent_child_pipe) < 0 || pipe(child_parent_pipe) < 0) 
    puts("Error creating pipes...\n"); 

if ((pid = fork()) < 0) 
    puts("Error forking...\n"); 
else if (pid > 0) { /* PARENT */ 
    close(parent_child_pipe[0]); 
    close(child_parent_pipe[1]); 
    while (fgets(line, MAXLINE, stdin) != NULL) { 
    n = strlen(line); 
    if (write(parent_child_pipe[1], line, n) != n) 
    puts("write error to pipe...\n"); 
    if ((n = read(child_parent_pipe[0], line, MAXLINE)) < 0) 
    puts("read error from pipe...\n"); 
    if (n == 0) { 
    puts("child closed pipe...\n"); 
    break; 
    } 
    line[n] = 0; /* null terminate */ 
    if (fputs(line, stdout) == EOF) 
    puts("fputs error...\n"); 
    } 
    if (ferror(stdin)) 
    puts("fgets error on stdin...\n"); 
    exit(0); 

} else { /* CHILD */ 
    close(parent_child_pipe[1]); 
    close(child_parent_pipe[0]); 
    if (parent_child_pipe[0] != STDIN_FILENO) { 
    if (dup2(parent_child_pipe[0], STDIN_FILENO) != STDIN_FILENO) 
    puts("dup2 error to stdin...\n"); 
    close(parent_child_pipe[0]); 
    } 
    if (child_parent_pipe[1] != STDOUT_FILENO) { 
    if (dup2(child_parent_pipe[1], STDOUT_FILENO) != STDOUT_FILENO) 
    puts("dup2 error to stdout...\n"); 
    close(child_parent_pipe[1]); 
    } 
    **if (execl("./child", "child", (char *) 0) < 0)** 
    puts("execl error...\n"); 
} 
} 

現在的「孩子」的計劃上面寫的C和只需通過STDIN接收流,操縱流,並將其發回了使用標準輸出。

喜歡的東西:

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

#define STDIN_FILENO 0  /* Standard input. */ 
#define STDOUT_FILENO 1  /* Standard output. */ 
#define STDERR_FILENO 2  /* Standard error output. */ 
#define MAXLINE 4096 

int main(void){ 
int n; 
char line[MAXLINE]; 

while ((n = read(STDIN_FILENO, line, MAXLINE)) > 0) { 
    line[n] = 0; /* null terminate */ 
    n = strlen(line); 
    if (write(STDOUT_FILENO, line, n) != n) 
    puts("write error"); 
} 
exit(0); 
} 

所以這是工作的罰款,但現在我希望能夠寫孩子的任何腳本語言如Python/Lua的等等。我怎樣才能做到這一點?我曾嘗試這樣的東西:

如果(EXECL( 「路徑蟒」, 「test.py」,(字符*)0)< 0)

但它只是似乎掛等待接收輸入?

有人可以幫助我嗎?我認爲PIPES可以和任何可以從STDIN讀取並返回STDOUT的Lua/Python進行通信?

UPDATE:

我已經取得了一些小的變化,現在,這裏是Python的文件:「NullFilter.py」,簡單地回聲它是什麼派:

#!/usr/bin/python 
import sys 

class NullFilter: 

     def execute(self): 
      #Read data from STDIN... 
      data = sys.stdin.read() 
      #Write data to STDOUT... 
      sys.stdout.write(data) 
      exit(0) 
if __name__ == '__main__': 
     nf = NullFilter() 
     nf.execute() 

而且現在的C代碼調用使用它:

... 
if (execl("/usr/bin/python","./NullFilter.py","./NullFilter.py",NULL, (char *) 0) < 0) 
puts("execl error...\n"); 
... 

當我現在運行它,我可以輸入文本,標準輸入,但是必須擊中CRTL-C,看看發生了什麼:下面是結果:

[email protected]:~/Desktop/pipe example$ ./parent 
hello 
hello again 
^CTraceback (most recent call last): 
    File "./NullFilter.py", line 17, in <module> 

nf.execute() 
    File "./NullFilter.py", line 10, in execute 
[email protected]:~/Desktop/pipe example$  data = sys.stdin.read() 
KeyboardInterrupt 

[email protected]:~/Desktop/pipe example$ 

更新2:

OK,所以我一直在玩弄一點,只是改變了Python代碼從 「sys.stdin.read()」 到 「sys.stdin.readline()」它似乎在一定程度上工作,但沒有完美...

#!/usr/bin/python 
import sys 

class NullFilter: 

     def execute(self): 
      #Read data from STDIN... 
      data = ""    
      for line in sys.stdin.readline(): 
       data = data + line 
      #Write data to STDOUT... 
      sys.stdout.write(data) 
      exit(0) 
if __name__ == '__main__': 
     nf = NullFilter() 
     nf.execute() 

這是一個解決方法,但不完美的。任何其他想法如何讓STDIN讀取流UNBUFFERED?我已經在Python看了看SELECT模塊:

http://docs.python.org/library/select.html

我也試圖通過「-u」到Python使「緩衝」,但仍然沒有運氣;-(

但可以肯定這不能這麼難嗎?

林頓

+0

只是出於好奇,你爲什麼不使用Python提供了與C接口API ?您可以使用它直接從C中調用Python代碼,而且非常靈活。 – avpx 2010-09-06 18:34:24

+0

您好,我知道Python中的C API,但這不是我正在尋找的。該應用程序實際上是一個C應用程序,我只是*希望*因爲我正在使用PIPES,我可以用Python或Lua等其他語言編寫一些「用戶出口」......但無論如何;-) – 2010-09-07 07:25:34

回答

4

經過多次玩耍並試圖刷新所有內容我意識到我需要關閉PIPE的STDOUT末端,孩子(後寫入過程中的管道)...

因此,代碼是現在:

#include <sys/types.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <unistd.h> 

#define STDIN_FILENO 0  /* Standard input. */ 
#define STDOUT_FILENO 1  /* Standard output. */ 
#define STDERR_FILENO 2  /* Standard error output. */ 
#define MAXLINE 4096 

int main(void){ 
int n, parent_child_pipe[2], child_parent_pipe[2]; 
pid_t pid; 
char line[MAXLINE]; 
int rv; 

if (pipe(parent_child_pipe) < 0 || pipe(child_parent_pipe) < 0) 
    puts("Error creating pipes...\n"); 

if ((pid = fork()) < 0) 
    puts("Error forking...\n"); 
else if (pid > 0) { /* PARENT */ 
    close(parent_child_pipe[0]); 
    close(child_parent_pipe[1]); 
    while (fgets(line, MAXLINE, stdin) != NULL) { 
    n = strlen(line); 
    if (write(parent_child_pipe[1], line, n) != n) 
    puts("write error to pipe...\n"); 
    close(parent_child_pipe[1]); 
    wait(&rv); 
    if ((n = read(child_parent_pipe[0], line, MAXLINE)) < 0) 
    puts("read error from pipe...\n"); 
    if (n == 0) { 
    puts("child closed pipe...\n"); 
    break; 
    } 
    line[n] = 0; /* null terminate */ 
    if (fputs(line, stdout) == EOF) 
    puts("fputs error...\n"); 
    } 
    if (ferror(stdin)) 
    puts("fgets error on stdin...\n"); 
    exit(0); 

} else { /* CHILD */ 
    close(parent_child_pipe[1]); 
    close(child_parent_pipe[0]); 
    if (parent_child_pipe[0] != STDIN_FILENO) { 
    if (dup2(parent_child_pipe[0], STDIN_FILENO) != STDIN_FILENO) 
    puts("dup2 error to stdin...\n"); 
    close(parent_child_pipe[0]); 
    } 
    if (child_parent_pipe[1] != STDOUT_FILENO) { 
    if (dup2(child_parent_pipe[1], STDOUT_FILENO) != STDOUT_FILENO) 
    puts("dup2 error to stdout...\n"); 
    close(child_parent_pipe[1]); 
    } 
    if (execl("./NullFilter.py", "./NullFilter.py", (char *) 0) < 0) 
    puts("execl error...\n"); 
} 
} 

你可以看到 「關閉(parent_child_pipe [1]);」在寫完上面的PIPE之後,這是我必須做的至關重要的一件事。這將迫使流被刷新到Python腳本,Lua腳本,C代碼等。

在上面你會看到我正在執行一個Python腳本「NullFilter.py」....

注意:如果您運行上面的代碼,它將適用於輸入/輸出的一次迭代,因爲Python腳本在第一次測試後關閉了管道,但是您需要在基礎上進行構建......

感謝所有幫助不過,我學到了很多東西,從這個練習;-)

林頓

1

我相信你可以做到你想做的事通過啓動與shebang行這樣的Python文件:

#!/usr/bin/python 

,並確保它是可執行的,然後使用腳本作爲在execl()

可執行現場見http://linux.about.com/od/commands/l/blcmdl2_execve.htm

文件名必須是二進制 可執行文件或以 開頭的腳本,格式爲「#!解釋器 [參數]」。在後一種情況下, 解釋器必須是可執行的有效路徑名 ,其本身不是 一個腳本,該腳本將被調用作爲 翻譯[參數]的文件名。

在傳遞參數的情況下(理論上也是有效的),它看起來並不像python實際上正在執行腳本並完成它應該的事情 - 而是它打開一個交互式終端,這就是它掛起的原因 - 它希望你通過stdin嘗試「test.py」的絕對路徑,看看會發生什麼,因爲它聽起來像是python找不到它。實際上有另一種方法。沒有理由不能通過管道將腳本逐行傳遞給解釋器並以此方式運行。

+0

嗨,那裏,感謝上面的輸入,而且我確實將#!/ usr/bin/python添加到了Python腳本的頂部。我會嘗試你的絕對路徑建議,並會很快回復你。注意:它實際上確實看起來Python可以找到該文件,因爲我輸入一些輸入後,擊中CTRL-C我在Python代碼中得到一個KeyboardInterrupt。它在「sys.stdin.read()」上定義爲HANGING。在寫完PIPE後,我試圖在C面上嘗試FFLUSH,但仍然沒有運氣;-( – 2010-09-07 07:26:59

0

你對孩子嘗試沖水嗎?

UPDATE:

我與你的C代碼,並與這兩個腳本(Perl和Python)和他們的行爲嘗試是完全一樣的C子元素在我的機器上

#!/usr/bin/perl -w 
use IO::Handle; 

while (<>) 
{ 
     print; 
     flush STDOUT; 
} 

而且

#!/usr/bin/python 
import sys 

class NullFilter: 
     def execute(self): 
       while True: 
         line=sys.stdin.readline() 
         if not line: break 
         sys.stdout.write(line) 
         sys.stdout.flush() 
       exit(0) 
if __name__ == '__main__': 
     nf = NullFilter() 
     nf.execute() 
+0

嗨,那裏,是的,我已經試過對孩子沖洗,但它甚至沒有到達那裏,它掛在「 sys.stdin.read()「 – 2010-09-08 05:55:52

+0

我甚至在寫入PIPE之後嘗試在C代碼上執行FFLUSH,沒有任何運氣;-( – 2010-09-08 06:01:28

+0

嗨,在那裏,是的READLINE工程,但只是把」sys.stdin。閱讀()「,看看會發生什麼......但感謝您的幫助;-) – 2010-09-09 06:36:58