2010-09-06 73 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