在Python子进程中使用反向标记

时间:2015-07-20 12:32:03

标签: python git bash subprocess popen

我想通过Python脚本运行这个git命令并获取它的输出:

git diff --name-only mybranch `git merge-base mybranch develop`

该命令的目的是查看自上次与develop合并以来对mybranch所做的更改。

要实现这一点,我正在使用subprocess.Popen

output = subprocess.Popen(["git", "diff", "--name-only", "mybranch", "`git merge-base mybranch develop`"], stdout=subprocess.PIPE, shell=True)

然而,这不起作用。变量output.communicate()[0]只是给我打印git用法 - 基本上告诉我输入命令是错误的。

我看到了类似的问题exists here,但它只告诉我使用shell=True并没有解决我的问题。

我也尝试连续运行这两个命令,但这给了我与以前相同的输出。但是,我可能在这一步中遗漏了一些东西。

感谢任何帮助或提示。

2 个答案:

答案 0 :(得分:2)

反引号和子进程

反引号是 shell功能,您可能无法选择但只能使用shell=True,但是传入一个shell命令字符串,而不是列表args

所以对于你的特定命令(假设它首先起作用)

process = subprocess.Popen("git diff --name-only mybranch `git merge-base mybranch develop`", stdout=subprocess.PIPE, shell=True)

请注意,当您致电Popen()时,您获得了一个流程,不应该被称为output IMO

这是一个使用反引号的简单示例

>>> process = subprocess.Popen('echo `pwd`', stdout=subprocess.PIPE, shell=True)
>>> out, err = process.communicate()
>>> out
'/Users/bakkal\n'

或者您可以使用$(cmd)语法

>>> process = subprocess.Popen('echo $(pwd)', stdout=subprocess.PIPE, shell=True)
>>> out, err = process.communicate()
>>> out
'/Users/bakkal\n'

这是不起作用的(针对反叛)

>>> process = subprocess.Popen(['echo', '`pwd`'], stdout=subprocess.PIPE, shell=True)
>>> out, err = process.communicate()
>>> out
'\n'
>>> process = subprocess.Popen(['echo', '`pwd`'], stdout=subprocess.PIPE, shell=False)
>>> out, err = process.communicate()
>>> out
'`pwd`\n'

答案 1 :(得分:2)

在POSIX上,参数列表传递给/bin/sh -c,即只有第一个参数被识别为shell命令,即shell运行git而没有任何参数,这就是为什么你会看到使用信息。如果要使用shell=True,则应将该命令作为字符串传递。来自the subprocess docs

  

在带有shell=True的POSIX上,shell默认为/bin/sh。如果args是   string,string指定通过shell执行的命令。   这意味着字符串必须完全按照原样进行格式化   在shell提示符下键入时。这包括,例如,引用或   反斜杠转义文件名,其中包含空格。如果args是   sequence,第一项指定命令字符串,以及任何   其他项目将被视为shell的附加参数   本身。也就是说,Popen相当于:

Popen(['/bin/sh', '-c', args[0], args[1], ...])

在这种情况下,您不需要shell=True

#!/usr/bin/env python
from subprocess import check_output

merge_base_output = check_output('git merge-base mybranch develop'.split(), 
                                 universal_newlines=True).strip()
diff_output = check_output('git diff --name-only mybranch'.split() +
                           [merge_base_output])