2014-07-14 23 views
2

我想编译一个使用Python的C程序,并且想要使用“<”运算符给出输入,但它不能按预期工作。 如果我编译C程序并通过给它输入一个文件来运行它,例如使用Python子进程调用C编译器命令

./a.out <inp.txt works 

但同样,如果我尝试使用Python脚本来做到这一点,它没有像预期的那样工作。 例如:

import subprocess 
subprocess.call(["gcc","a.c","-o","x"]) 
subprocess.call(["./x"]) 

import subprocess 
subprocess.call(["gcc","a.c","-o","x"]) 
subprocess.call(["./x","<inp.txt"]) 

两个脚本询问虽然终端输入。但我认为在第二个脚本中它应该从文件中读取。为什么这两个程序都是一样的?

回答

5

为了补充@Jonathan Leffler's@alastair's有用的答案:

假设控制你传递给shell执行字符串,我认为没有错用外壳以方便使用。 [1]

subprocess.call()具有可选的布尔shell参数,这将导致该命令被传递到,使I/O重定向,引用环境变量,...:

subprocess.call("./x <inp.txt", shell = True) 

整个命令行是如何作为单个而不是参数数组传递。


[1]在下列情况下 避免使用的shell:

  • 如果你的Python代码必须在平台上运行其他比Unix类的,如Windows
  • 如果性能是最重要的。
  • 如果您发现自己的“外包”任务能够在Python方面得到更好的处理。

如果你担心缺乏shell环境的可预测性(如@alastair是):

  • subprocess.callshell = True总是创建的非交互式非登录实例/bin/sh - 请注意,它不是用户使用的默认外壳。
  • sh不读取初始化文件用于非交互式非登录shell(既不是系统范围也不是用户特定的)。
    • 注意,即使在平台上,其中shbash伪装,bash当为sh调用将这样的行为。
  • subprocess.call创造了shell = True每一个shell实例是自己的世界,其环境既不是以前的shell实例的影响也不会影响到后来者。
  • 然而,壳实例创建继承环境蟒蛇过程本身的:
    • 如果从交互shell启动你的Python程序,然后shell的环境中继承。请注意,这只有属于当前工作目录环境变量,而不是别名,shell函数和shell变量。
    • 一般情况下,这是一个功能,给出了Python(CPython的)本身的设计是通过环境变量控制的(对于2.x,请参见https://docs.python.org/2/using/cmdline.html#environment-variables;为3.x中,看到https://docs.python.org/3/using/cmdline.html#environment-variables)。
    • 如果需要,你可以提供自己的环境经由env参数外壳;但是,请注意,如果需要,您将必须提供整个环境,如果需要,可能会包括变量,例如USERHOME;如果需要,可能包括变量,如USERHOME。简单的例子,定义$PATH明确:
    • subprocess.call('echo $PATH', shell = True, \ env = { 'PATH': '/sbin:/bin:/usr/bin' })
+0

有“没有错,使用shell为了方便”?你会这么想,但如果例如用户设置IFS?或者,因为上面给gcc的调用没有指定完整路径,PATH?如果可以避免的话,最好不要使用shell来运行。 – alastair

+0

@alastair:'$ IFS'或'$ PATH'只能从你正在执行的shell命令中改变(临时);看我的更新如何创建shell实例,并让我知道如果你仍然担心修改后的环境(我可能会错过一些东西)。也就是说,如果您还需要支持Windows(除非您故意只使用足够简单的命令以在两种平台类型上工作),那么避免shell的一个有说服力的理由是。 – mklement0

+0

根据'subprocess'文档,除非明确指定环境,否则它是从Python进程继承的。如果某人可以操纵* that *过程的环境,它仍可能导致不需要的行为。 – alastair

4

shell执行进程的I/O重定向。根据你所说的,subprocess模块不会像那样做I/O重定向。为了演示,运行:

subprocess.call(["sh","-c", "./x <inp.txt"]) 

运行shell并重定向I/O。用你的代码,你的程序./x正在被给出一个它忽略的参数<inp.txt

注意:subprocess.call的替代呼叫纯粹用于诊断目的,而不是推荐的解决方案。推荐的解决方案包括阅读(Python 2)subprocess模块文档(或文档Python 3)以了解如何使用模块进行重定向。

import subprocess 
i_file = open("inp.txt") 
subprocess.call("./x", stdin=i_file) 
i_file.close() 

如果你的脚本是要退出的,所以你不必担心浪费的文件描述符,你可以压缩到:

import subprocess 
subprocess.call("./x", stdin=open("inp.txt")) 
2

默认情况下,subprocess模块未通过参数给shell。为什么?因为通过shell运行命令是危险;除非它们被正确地引用和转义(这很复杂),否则通常可以说服那些做这种事情的程序运行不需要的和意外的shell命令。

无论如何,使用shell将是错误的。如果要从特定文件获取输入,可以使用subprocess.Popen,将stdin参数设置为文件inp.txt的文件描述符(您可以通过调用fileno() Python文件对象来获取文件描述符)。

相关问题