【问题标题】:Why is subprocess.call("""scp foo""") broken?为什么 subprocess.call("""scp foo""") 坏了?
【发布时间】:2012-10-02 13:55:43
【问题描述】:

成功:

>>> scp_cmd = r"sudo scp -i /home/backup/.ssh/id_rsa /opt/backups/*conf backup@a-hostname.local:/opt/backups/"
>>> subprocess.call(scp_cmd, shell=True)
1eadmin1.conf                                                  100%   83KB  83.5KB/s   00:00
1stflr_1.conf                                                  100% 2904     2.8KB/s   00:00
>>> scp_cmd = """sudo scp -i /home/backup/.ssh/id_rsa /opt/backups/*conf backup@a-hostname.local:/opt/backups/"""
>>> os.system(scp_cmd)
1eadmin1.conf                                                  100%   83KB  87.3KB/s   00:00
1stflr_1.conf                                                  100% 2904     3.4KB/s   00:00

失败:

>>> scp_cmd = r"""sudo scp -i /home/backup/.ssh/id_rsa /opt/backups/*conf backup@a-hostname.local:/opt/backups/"""
>>> subprocess.call(scp_cmd, shell=True)
/opt/backups/*conf: No such file or directory
1
>>> subprocess.call(scp_cmd.split(' '))
/opt/backups/\*conf: No such file or directory
1
>>>
>>> subprocess.call(shlex.split(scp_cmd))
/opt/backups/*conf: No such file or directory
1

我很困惑为什么三引号在我使用 subprocess.call() 时会失败,但在我使用 os.system() 时会通过。为什么subprocess.call()os.system() 在处理三引号字符串时会有区别?

【问题讨论】:

    标签: python shell subprocess os.system


    【解决方案1】:

    我很确定你正在做一些不同的事情;三重引用在这里根本没有什么区别:

    >>> a = r"sudo scp -i /home/backup/.ssh/id_rsa /opt/backups/*conf backup@a-hostname.local:/opt/backups/"
    >>> b = r"""sudo scp -i /home/backup/.ssh/id_rsa /opt/backups/*conf backup@a-hostname.local:/opt/backups/"""
    >>> a == b
    True
    >>> b
    'sudo scp -i /home/backup/.ssh/id_rsa /opt/backups/*conf backup@a-hostname.local:/opt/backups/'
    >>> a
    'sudo scp -i /home/backup/.ssh/id_rsa /opt/backups/*conf backup@a-hostname.local:/opt/backups/'
    

    使用三引号只是一种 指定python 字符串文字的方式。您如何指定该文字(带或不带 r 原始前缀,带单引号或三引号,使用单 ' 或双 " 引号)不会被保留。

    三重引号 的不同之处在于您包含换行符:

    >>> foo = '''
    ... '''
    >>> foo
    '\n'
    

    但是您的示例根本不包含任何换行符。

    【讨论】:

    • 确实,第一个'Success'示例根本行不通。它需要shell=True 或者需要拆分命令。
    • @MikePennington:我觉得这很难相信。 其他东西也发生了变化。
    • @Rob,你是对的,我在问题中解决了这个问题;但是,这并没有改变我在尝试使用三引号 scp 时失败的现实
    • @MikePennington:我知道;关键是这是三引号的唯一区别;它可以很容易地在你的字符串文字中包含换行符,并且可以很容易地包含(单)引号文字。 没有其他区别,产生的字符串在其他方面是相同的。因此,您是在找错树了。
    • @MikePennington,这会失败,因为如果你这样运行它就没有外壳扩展。
    【解决方案2】:

    +1 对 Martijn 所说的一切,我想我可能知道发生了什么。这个输出:

    >>> subprocess.call(scp_cmd.split(' '))
    /opt/backups/\*conf: No such file or directory
    

    在我看来很可疑。 为什么会有反斜杠?

    尽我所能匹配您的命令,我得到类似 [仅抑制用户名]:

    >>> import subprocess, shlex
    >>> 
    >>> subprocess.call(r"scp -i /home/user/.ssh/id_rsa /tmp/*conf user@localhost:/tmp/save", shell=True)
    aconf                                    100%    4     0.0KB/s   00:00    
    bconf                                    100%    9     0.0KB/s   00:00    
    0
    >>> subprocess.call(r"""scp -i /home/user/.ssh/id_rsa /tmp/*conf user@localhost:/tmp/save""", shell=True)
    aconf                                    100%    4     0.0KB/s   00:00    
    bconf                                    100%    9     0.0KB/s   00:00    
    0
    

    这是有效的,因为如上所述,它们是相同的字符串。但是说你不小心在里面放了一个反斜杠?你会得到

    >>> subprocess.call(r"""scp -i /home/user/.ssh/id_rsa /tmp/\*conf user@localhost:/tmp/save""", shell=True)
    /tmp/*conf: No such file or directory
    1
    >>> subprocess.call(r"""scp -i /home/user/.ssh/id_rsa /tmp/\*conf user@localhost:/tmp/save""".split(" "))
    /tmp/\*conf: No such file or directory
    1
    >>> subprocess.call(shlex.split(r"""scp -i /home/user/.ssh/id_rsa /tmp/\*conf user@localhost:/tmp/save"""))
    /tmp/*conf: No such file or directory
    1
    

    与您的输出完全匹配——shell=Trueshlex.split() 的输出中没有反斜杠,但.split(" ") 有反斜杠。为了比较,如果没有反斜杠,你应该得到错误消息

    >>> subprocess.call(r"""scp -i /home/user/.ssh/id_rsa /tmp/*conf user@localhost:/tmp/save""".split(" "))
    /tmp/*conf: No such file or directory
    1
    

    所以在我看来,您发布的 scp_cmd 很可能不是您的输出实际对应的那个,并且您的真实输出有一个反斜杠。

    【讨论】:

    • 当然,当您在 20 分钟内排除故障时,在问题中发布所有 20 分钟的调试是没有意义的...是的,我在 * 上尝试了反斜杠转义,不,这并没有导致问题
    • @MikePennington:尊敬的,我不明白您发布的scp_cmd 不包含反斜杠,与您发布的输出兼容,它确实如此。我已经在上面展示了一个初步的案例,即插入一个会生成你的输出,而不插入一个不会。
    • 你已经证明这个问题并没有反映我测试的每一个案例,而且我不完美地把问题组合在一起。为此我道歉......无论如何,你的结论是有缺陷的。也有错误的原始脚本从来没有反斜杠。
    猜你喜欢
    • 2014-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多