在Python中执行Bash命令

时间:2014-06-24 11:54:00

标签: python perl bash

在bash中考虑以下命令:

multi-bleu.perl reference < mt-output

我有两个问题:

  1. 这到底发生了什么?我的理解是referencemt-output不是参数,但它们以某种方式写入stdin。因此,如果它们是文件,它们的内容是否会写入stdin
  2. 如何在Python脚本中运行它,并获取Perl脚本的结果?
  3. 我的尝试不起作用。包含在文件test.py中:

    from subprocess import Popen, PIPE
    import settings
    
    command = settings.BLEU + " " + settings.CORPUS + " < " + settings.HYPOTHESIS
    print command
    pipe = Popen(command, stdin=PIPE, stdout=PIPE)
    output = pipe.communicate()[0]
    print output
    

    我运行与运行test.py相同的文件夹中打印的命令。前者是作品,后者则不是。错误回溯如下:

    Traceback (most recent call last):
      File "/Users/[...]/tests.py", line 6, in <module>
        pipe = Popen([command], stdin=PIPE, stdout=PIPE)
      File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 711, in __init__
        errread, errwrite)
      File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 1308, in _execute_child
        raise child_exception
    OSError: [Errno 2] No such file or directory
    

2 个答案:

答案 0 :(得分:3)

你的bash / perl示例会发生什么取决于perl脚本正在做什么。有关bash方面发生的事情的解释,请参阅以下内容:

[sugarcube->temp]echo "Foo" > foo
[sugarcube->temp]echo "Bar" > bar
[sugarcube->temp]cat foo < bar
Foo
[sugarcube->temp]cat foo
Foo
[sugarcube->temp]cat bar
Bar
[sugarcube->temp]cat foo - < bar
Foo
Bar

我在这里创建了两个文件foobar<执行redirection of file contents to stdin。但是,在第一个cat示例中,cat没有获取(重定向文件的内容)barcat需要一个显式参数-,告诉它从stdin读取输入。

因此,在您的示例中,reference只是perl脚本的一个参数(可能只是将其作为文件打开)。 mt-output的内容被重定向到stdin,因此如果Perl脚本从stdin读取,它将处理它。

如果你想在Python中实现类似的东西,你的Python脚本只需要打开它接收的任何文件作为它的第一个参数(你可能要考虑argparse对命令行程序进行常规参数解析,虽然这个特殊问题可能有点过分了)。要处理来自stdin的数据,只需从sys.stdin读取。

答案 1 :(得分:3)

reference确实是一个正常的命令行参数;它的语义取决于被调用的程序。它可能是文件名(输入或输出),命令或其他任何内容。

现在,有两种方法可以调用Popen()

  1. shell=False(默认值):

    with open('mt-output', 'r') as infile:
        pipe = Popen(['multi-bleu.perl', 'reference'], stdin=infile, stdout=PIPE)
    

    RESP。

    with open(settings.HYPOTHESIS, 'r') as infile:
        pipe = Popen([settings.BLEU, settings.CORPUS], stdin=infile, stdout=PIPE)
    

    在这里,您可以打开要自己阅读的文件,然后传递打开的文件,使其成为流程&#39;标准输入。

    直接调用给定的文件。

  2. shell=True

    command = settings.BLEU + " " + settings.CORPUS + " < " + settings.HYPOTHESIS
    pipe = Popen(command, stdout=PIPE)
    

    在这里,您将所有操作都放在程序和要调用的程序之间的shel上。因此,您不会给出一个参数列表,而是一个命令行。

    stdin重定向也由shell执行。

  3. 第二种解决方案可能看起来更简单,但根据settings中的数据来源以及它们的外观,它可能非常危险。