“ git tag -l v1.1。{[0-9],[0-9] [0-9]}”在shell中有效,但在subprocess.Popen()中无效

时间:2018-12-27 23:27:23

标签: python subprocess

当我在外壳中运行git tag -l v1.1.{[0-9],[0-9][0-9]}时,我会得到结果,但是

def run_command(cmd_args, number_of_retry=5,
                timeout_in_second=90, suppress_output=False):
    proc = subprocess.Popen(cmd_args,
                            stdin=subprocess.PIPE,
                            stdout=subprocess.PIPE,
                            stderr=subprocess.PIPE)

    timer = threading.Timer(timeout_in_second, proc.kill)

    timer.start()
    out, err = proc.communicate()
    timer.cancel()

    if proc.returncode and number_of_retry >= 1:
        if not suppress_output:
            print('Command "{}" failed/timeout, retrying...'.format(
                ' '.join(cmd_args)))
        return run_command(cmd_args,
                           number_of_retry - 1,
                           timeout_in_second + 10,
                           suppress_output=suppress_output)

    return proc.returncode, out, err

return_code, out, _ = run_command(
    ['git', 'tag', '-l', "v1.1.{[0-9],[0-9][0-9]}"],
    number_of_retry=0,
    suppress_output=False)

无结果。将我的代码中的模式更改为v1.1。[0-9] [0-9]会产生匹配的结果,与v1.1。[0-9]一样,因此括号中存在问题。有人知道这怎么可能吗?还有另一种方式来表达相同的表达式,或者至少看到bash子进程正在运行,以便可以验证是否正在运行正确的命令吗? (子进程和线程是python模块)

1 个答案:

答案 0 :(得分:2)

v1.1.{[0-9],[0-9][0-9]}中的花括号和逗号语法(“花括号扩展”)是对shell的指令,而不是对git的指令;它告诉外壳程序将参数拆分为两个(此后,由于它们包含未加引号的glob字符,因此外壳程序默认情况下会尝试将每个结果参数扩展为glob-希望您实际上并不打算这样做,并且因此不必介意它消失了),然后传递git两个单独的参数,一个用于大括号内逗号两侧的内容。

缺少先前讨论的遍历,此shell扩展的结果等效于以下Python代码:

run_command(['git', 'tag', '-l', 'v1.1.[0-9]', 'v1.1.[0-9][0-9]'],
            number_of_retry=0, suppress_output=False)

如果您实际上是 do 依靠外壳程序将v1.1.[0-9]替换为当前目录中与该模式匹配的条目列表(如果存在任何此类条目,则本机Python等效项为)更像是:

# to behave like default bash behavior (without running ''shopt -s nullglob''):
import glob
def expandGlob(word):
    return glob.glob(word) or [word]

run_command(['git', 'tag', '-l'] + expandGlob('v1.1.[0-9]') + expandGlob('v1.1.[0-9][0-9]'),
            number_of_retry=0, suppress_output=False)