Subprocess.popen()不能在Windows上的参数中使用引号

时间:2015-04-03 15:20:06

标签: python windows subprocess call popen

我在帖子上搜索了SO,寻找一种方法,使用subprocess.popen在参数内部使用引号,我似乎无法找到方法。

这可以从命令行

中正常工作
runme.bat --include="check|check2"

的Python

#!/usr/bin/python
import sys
import subprocess
import shlex

#command_line = "./runme.sh --include=\"check|check2\""
command_line = "runme.bat --include=\"check|check2\""

arg = shlex.shlex(command_line)
arg.quotes = '"'
arg.whitespace_split = True
arg.commenters = ''
command_line_args = list(arg)
print command_line_args

command_line_process = subprocess.Popen(
    command_line_args,
    universal_newlines=True,
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE
)

line = ""
while True:
    line = command_line_process.stdout.readline()
    if line:
        print line
        break

runme.bat

echo %* >> someargs.txt

runme.sh

#!/bin/bash
echo $@

我听说subprocess.call()是解决这个问题的方法,但是我希望能够在子进程中逐行迭代'在程序运行时输出

修改

这似乎是Python中的一个错误,因为在cmd中运行runme.bat工作正常,在linux中运行runme.py可以正常工作,只有在Windows上运行runme.py并且它没有运行时才会这样做工作正常。我创建了一张票here

EDIT2:

它显然不是一个python bug。看看选择的答案。

3 个答案:

答案 0 :(得分:4)

在Windows上,字符串是本机API。为避免不必要的转换,请将命令作为字符串传递:

#!/usr/bin/env python
from __future__ import print_function
import subprocess

command = 'runme.bat --include="check|check2"'
process = subprocess.Popen(command,
    stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
    universal_newlines=True, bufsize=1)
for line in iter(process.stdout.readline, ''):
    print(line, end='')

stderr=subprocess.STDOUT将stderr合并到stdout中。如果您设置了stderr=PIPE,那么您应该从{{1>}中读取process.stderr并阅读process.stdout,否则您的程序可能会陷入僵局。

Popen()将字符串传递给CreateProcess() Windows函数。如果子进程实际上是批处理文件;你可能应该明确地传递shell=True,以明确命令使用cmd.exe规则进行解释(^|等是元字符,更多详情{{ 3}})。

如果您想使用%1而不是%*传递参数,以便它包含
整个--include="check|check2"(不仅仅是--include)然后您可以在参数周围使用其他引号read the links in this answer

command = '"runme.bat" "--include="check^^^|check2""'

注意:要在此处转发^三倍|

答案 1 :(得分:3)

您应使用shell=True来运行bat文件。如果必须运行一些内置的shell命令,请仅使用 。换句话说,您正在使用它是无用的,唯一的影响是增加程序的安全漏洞。

另请注意,documentation明确指出,使用shell=True时,建议将命令行作为字符串传递:

  

如果 shell True,建议将 args 作为字符串传递   而不是一个序列。

所以你应该这样做:

subprocess.check_output('runme.bat --include="check|check2"', shell=True)

如果您只关心输出,则应使用check_output函数。它比创建Popen对象然后手动读取输出更简单。

另请参阅my answer,了解shell=True如何更改参数的含义。

答案 2 :(得分:0)

获得输出的另一种方法是subprocess.check_output()

import subprocess

command_line = "runme.bat --include=\"check|check2\""
output = subprocess.check_output(
    command_line,
    shell=True
)
lines = output.splitlines(True)
print lines

要实时查看流程的输出,请参阅:Getting realtime output using subprocess

编辑:这里的代码与Popen处理双引号:

from subprocess import Popen, PIPE, STDOUT

command_line = 'ls -la | grep "wheel"'
p = Popen(command_line, stdout=PIPE, stderr=STDOUT, shell=True)
while True:
    line = p.stdout.readline()
    if not line:
        break
    else:
        print line