【问题标题】:Using back-ticks in Python subprocess在 Python 子进程中使用反引号
【发布时间】:2015-10-09 13:58:24
【问题描述】:

我想通过 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,这并没有解决我的问题。

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

感谢任何帮助或提示。

【问题讨论】:

  • 您为什么要尝试使用 shell=True 并传递参数列表?还有为什么 git 在一个单独的列表中?`
  • 链接问题中的答案说使用反引号仅适用于 shell=True。它们在单独的列表中没有特别的原因,我会编辑以避免混淆。
  • 您应该使用带有 shell=True 的字符串或删除 shell=True 并传递单个参数列表
  • 谢谢,这就是答案。我一定在文档中错过了这个。
  • 请注意,Bash 中不推荐使用反引号:$(cmd) 语法不太容易被误读,如有必要,您可以嵌套它。请参阅BashFAQ/082“为什么 $(...) 优于(反引号)?”在 BashGuide 中了解更多详细信息。此外,反引号在 SO cmets 中写起来很痛苦。 :)

标签: python git bash subprocess popen


【解决方案1】:

反引号和子进程

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

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

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

请注意,当您调用 Popen() 时,您会得到一个进程,不应将其称为 outputIMO

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

>>> 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'

【讨论】:

  • @PM2Ring 添加了使用$(cmd)subprocess 的示例
  • 谢谢。我决定将我的评论移到这个问题上,因为那里可能更合适。
  • 个选择,你可以drop shell=True
  • 您必须手动进行反引号扩展,因为从我的试验来看,如果没有 shell=True,您似乎无法扩展反引号或 $(cmd),反引号是问题的症结跨度>
【解决方案2】:

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

在带有shell=True 的POSIX 上,shell 默认为/bin/sh。如果args 是 string,字符串指定要通过shell执行的命令。 这意味着字符串必须完全按照它的格式进行格式化 在 shell 提示符下键入时。这包括,例如,引用或 反斜杠转义带有空格的文件名。如果args 是 序列,第一项指定命令字符串,任何 附加项将被视为 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])

【讨论】:

    猜你喜欢
    • 2014-09-28
    • 2017-12-06
    • 2022-08-03
    • 2016-07-22
    • 2016-07-08
    • 1970-01-01
    • 1970-01-01
    • 2010-11-07
    相关资源
    最近更新 更多