使用python将带有撇号的文件名传递给scp

eva*_*njd 2 python bash scp

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

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

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

这适用,但包含撇号的文件名除外.

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

scp -c blowfish -C user@host:"'/media/sdi1/home/data/bob'"'"'s file.avi'" /storage/downloads/incoming/
Run Code Online (Sandbox Code Playgroud)

而错误:

sh: -c: line 0: unexpected EOF while looking for matching `''
sh: -c: line 1: syntax error: unexpected end of file
Run Code Online (Sandbox Code Playgroud)

它看起来像pipes.quote(x)正在逃避撇号(应该如此),但显然语法仍然不正确.我已经尝试过丢弃pipes.quote(x)并用/'替换撇号,但这也没有让我到任何地方.

Jo *_* So 6

由于scp是基于SSH,你给它的文件名是受壳逸出在远程的一面.因此你需要逃脱两次.

shell的正确转义的cmdline:

scp -c blowfish -C user@host:"\"/media/sdi1/home/data/bob's file\"" /storage/.../
Run Code Online (Sandbox Code Playgroud)

要创建一个python字符串,我们必须再添加一个转义级别.为了保持理智,我们可以使用三引号:

"""scp -c blowfish -C user@host:"\"/media/sdi1/home/data/bob's file\"" /storage/.../"""
Run Code Online (Sandbox Code Playgroud)

如果以编程方式执行此操作(例如使用已弃用的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)
Run Code Online (Sandbox Code Playgroud)

这无疑令人困惑.对于一个简单的模型,整个要点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)
Run Code Online (Sandbox Code Playgroud)

它更清楚地表达了意图:控制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)
Run Code Online (Sandbox Code Playgroud)