首页 > 解决方案 > 如何引用 subprocess.run 列表的一部分?

问题描述

我需要引用 subprocess.run 使用的包含 ssh 参数的 rsync 行的一部分,不幸的是,到目前为止我没有尝试过任何工作。

有人可以告诉我引用 ssh 参数的正确方法,以便它可以在 rsync 下运行。

起初,我有一个传递给 subprocess.run 的列表列表,但失败了:

Traceback (most recent call last):
  File "./tmp.py", line 20, in <module>
    process = subprocess.run(rsync_cmd, stderr=subprocess.PIPE)
  File "/usr/lib/python3.6/subprocess.py", line 423, in run
    with Popen(*popenargs, **kwargs) as process:
  File "/usr/lib/python3.6/subprocess.py", line 729, in __init__
    restore_signals, start_new_session)
  File "/usr/lib/python3.6/subprocess.py", line 1295, in _execute_child
    restore_signals, start_new_session, preexec_fn)
TypeError: expected str, bytes or os.PathLike object, not list

将其展平为普通列表:

Unexpected remote arg: example.com:/var/log/maillog
rsync error: syntax or usage error (code 1) at main.c(1361) [sender=3.1.2]

这是有道理的,因为需要引用 rsync 命令行的一部分。

所以我尝试引用它:

rsync: Failed to exec /usr/bin/ssh -F /home/rspencer/.ssh/config -o PreferredAuthentications=publickey -o StrictHostKeyChecking=accept-new -o TCPKeepAlive=yes -o ServerAliveInterval=5 -o ServerAliveCountMax=24 -o ConnectTimeout=30 -o ExitOnForwardFailure=yes -o ControlMaster=autoask -o ControlPath=/run/user/1000/foo-ssh-master-%C -l root -p 234 -o Compression=yes: No such file or directory (2)
rsync error: error in IPC code (code 14) at pipe.c(85) [Receiver=3.1.2]
rsync: connection unexpectedly closed (0 bytes received so far) [Receiver]
rsync error: error in IPC code (code 14) at io.c(235) [Receiver=3.1.2]

我希望这是因为它是一个字符串而不是一个列表。尽管我在猜测,但这对我来说并不完全有意义。

我最后一次尝试的总结代码:

#!/usr/bin/python3

import subprocess

ssh_args = [
    "-F",
    "/home/rspencer/.ssh/config",
    "-o",
    "PreferredAuthentications=publickey",
    "-o",
    "StrictHostKeyChecking=accept-new",
    "-o",
    "TCPKeepAlive=yes",
    "-o",
    "ServerAliveInterval=5",
    "-o",
    "ServerAliveCountMax=24",
    "-o",
    "ConnectTimeout=30",
    "-o",
    "ExitOnForwardFailure=yes",
    "-o",
    "ControlMaster=autoask",
    "-o",
    "ControlPath=/run/user/1000/foo-ssh-master-%C",
    "-l",
    "root",
    "-p",
    "234",
]
rsync_params = []
src = "example.com:/var/log/maillog"
dest = "."

# Build SSH command
ssh_cmd = ["/usr/bin/ssh"] + ssh_args

# Use basic compression
ssh_cmd.extend(["-o", "Compression=yes"])

ssh_cmd = " ".join(ssh_cmd)
ssh_cmd = f'"{ssh_cmd}"'

# Build rsync command
rsync_cmd = ["/usr/bin/rsync", "-vP", "-e", ssh_cmd] + rsync_params + [src, dest]

# Run rsync
process = subprocess.run(rsync_cmd, stderr=subprocess.PIPE)

if process.returncode != 0:
    print(process.stderr.decode("UTF-8").strip())

命令行上正确的命令是什么样的:

/usr/bin/rsync -vP -e "/usr/bin/ssh -F /home/rspencer/.ssh/config -o \
PreferredAuthentications=publickey -o StrictHostKeyChecking=accept-new -o \
TCPKeepAlive=yes -o ServerAliveInterval=5 -o ServerAliveCountMax=24 -o \
ConnectTimeout=30 -o ExitOnForwardFailure=yes -o ControlMaster=autoask \
-o ControlPath=/run/user/1000/foo-ssh-master-%C -l root -p 234 -o \
Compression=yes" example.com:/var/log/maillog .

标签: python-3.xlinuxsshsubprocessrsync

解决方案


事实证明,诀窍是不要试图引用它。

我删除了以下行,它无需进一步修改即可工作:

ssh_cmd = f'"{ssh_cmd}"'

我已经阅读了很多文档并且在提出问题之前一直错过它。墨菲。

重读帖子“ How not to quote argument in subprocess? ”并最终理解 Greg Hewgill 所说的对我有帮助。我责怪睡眠不足。

“如果您在 shell 命令行上使用引号,则将整个内容放在args(不带引号)的一个元素中。...” - Greg Hewgill


推荐阅读