【问题标题】:Passing a filename with an apostrophe into scp using python使用python将带有撇号的文件名传递给scp
【发布时间】:2012-11-26 21:25:23
【问题描述】:

我正在尝试编写一个 python 脚本来通过 scp 将文件从远程服务器复制到本地目录。

因为我在 OpenELEC 发行版上运行它(最小的 HTPC linux 发行版,只读文件系统除了 userhome 使得安装 python ssh 模块不切实际),我这样做很丑陋,只是将文件名传递给 scp通过 os.system 命令。

SCPCopy = "scp -c blowfish -C user@host:\"" + pipes.quote(file) + "\" /storage/downloads/incoming/"
SCPCopy = SCPCopy.replace('\n','')
os.system(SCPCopy)

这有效,但包含撇号的文件名除外。

以下是在带有撇号的文件中传递给 os.system 的示例:

scp -c blowfish -C user@host:"'/media/sdi1/home/data/bob'"'"'s file.avi'" /storage/downloads/incoming/

还有错误:

sh: -c: line 0: unexpected EOF while looking for matching `''
sh: -c: line 1: syntax error: unexpected end of file

看起来 pipe.quote(x) 正在转义撇号(应该如此),但显然语法仍然不正确。我已经尝试过放弃 pipe.quote(x) 并用 /' 替换撇号,但这也没有让我得到任何结果。

【问题讨论】:

  • Python 文档说 pipes.quote 自 1.6 版起已弃用!
  • 我试过不使用pipes.quote,而是像这样替换撇号:SCPCopy = SCPCopy.replace("'", "\'") 但是,我得到了同样的错误。
  • 使用shlex.quote,不要使用你自己的\"
  • 或者您可以重命名您的文件以不使用撇号。祝你好运。

标签: python bash scp


【解决方案1】:

由于scp 基于SSH,因此您为其提供的文件名也会在远程端进行shell 转义。因此你需要逃跑两次。

正确转义的 shell 命令行:

scp -c blowfish -C user@host:"\"/media/sdi1/home/data/bob's file\"" /storage/.../

要创建一个 python 字符串,我们必须再添加一层转义。为了保持清醒,我们可以使用三引号:

"""scp -c blowfish -C user@host:"\"/media/sdi1/home/data/bob's file\"" /storage/.../"""

如果您以编程方式执行此操作(例如,使用已弃用的 pipes.quote),则根本不要触摸文件名(在上面的示例中,您在文件名周围添加了撇号)。

fp = "/media/sdi1/home/data/bob's file.avi"
fp = "user@host:" + pipes.quote(pipes.quote(fp))

cmdline = "scp -c blowfish -C " + fp + " /storage/downloads/incoming/"
os.system(cmdline)

这确实令人困惑。对于一个简单的模型,pipes.quote 的全部意义在于对输入进行转义,以便 shell 将输入准确解析为 一个单词,即 等于输入强>。

以下是更普遍正确的方法(并产生相同的结果):

fp = "/media/sdi1/home/data/bob's file.avi"
# the filepath argument escaped for ssh/scp on the remote side
fp = pipes.quote(fp)
commandargs = ["scp", "-c", "blowfish", "-C", "user@host:"+fp, "/storage/downloads/incoming/"]
# escape all words for the local shell, and then concatenate space-separated
cmdline = " ".join(map(pipes.quote, commandargs))
os.system(cmdline)

它更清楚地表达了意图:控制 shell 将准确解析哪些单词。

但是为什么首先要从 shell 开始呢?我们不需要一个并且可以在本地保存转义。要使用我们的 args 直接生成一个进程,请使用来自 os.exec* 系列的命令。

fp = pipes.quote("/media/sdi1/home/data/bob's file.avi")
commandargs = ["scp", "-c", "blowfish", "-C", "user@host:"+fp, "/storage/downloads/incoming/"]
if os.fork() == 0:
    os.execvp("scp", commandargs)

【讨论】:

  • 太好了,谢谢 - 成功了。我确实必须将 user@host 移动到 cmdline 字符串,因为 pipe.quote 正在向用户名添加撇号。编辑:刚刚注意到您的更新 - 非常有用,谢谢!
猜你喜欢
  • 2021-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-21
  • 2012-09-12
  • 2011-12-20
  • 1970-01-01
相关资源
最近更新 更多