问题描述
我想写一个python脚本通过SCP从远程服务器复制文件到本地目录。
I'm trying to write a python script to copy files from a remote server to a local directory via scp.
由于我在一个OpenELEC分布在运行此(最小的HTPC的Linux发行版,除了USERHOME使得它不切实际的安装python SSH模块只读文件系统),我在做这个丑陋的,只是路过的文件名到SCP通过使用os.system命令。
Because I'm running this on an OpenELEC distribution (minimal HTPC linux distro, read-only filesystem except for userhome makes it impractical to install python ssh module), I'm doing this ugly and just passing the filename to the scp command via os.system.
SCPCopy = "scp -c blowfish -C user@host:\"" + pipes.quote(file) + "\" /storage/downloads/incoming/"
SCPCopy = SCPCopy.replace('\n','')
os.system(SCPCopy)
这个工作,除了包含撇号文件名。
This works, except for filenames containing an apostrophe.
下面是什么被传递与撇号的文件来使用os.system一个例子:
Below is an example of what gets passed to os.system in a file with an apostrophe:
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
看起来pipes.quote(x)的转义撇号(因为它应该),但很明显的语法仍然不正确。我已经尝试抛弃pipes.quote(X)和/'替换撇号但没有得到任何地方我不是。
It looks pipes.quote(x) is escaping the apostrophe (as it should), but obviously the syntax is still incorrect. I've experimented ditching pipes.quote(x) and replacing apostrophes with /' but that isn't getting me anywhere either.
推荐答案
由于 SCP
基于 SSH
,你给它的文件名是受到壳逸出遥控器上的一面。因此,你需要转义两次。
As scp
is based on SSH
, the filenames you give to it are subject to shell escaping on the remote side as well. Thus you need to escape twice.
一个正确转义为外壳CMDLINE:
A correctly escaped cmdline for the shell:
scp -c blowfish -C user@host:"\"/media/sdi1/home/data/bob's file\"" /storage/.../
要做出一个Python字符串,我们必须添加逃避的又一个层次。为了保持清醒,我们可以使用三重引号:
To make a python string, we have to add one more level of escaping. To stay sane, we could use triple-quotes:
"""scp -c blowfish -C user@host:"\"/media/sdi1/home/data/bob's file\"" /storage/.../"""
如果你这样做编程方式(例如,使用pcated去$ P $ pipes.quote
),那么就不要碰在所有的文件名(在你上面的例子,您添加周围的撇号文件名)。
If you do it programmatically (e.g. using the deprecated pipes.quote
), then don't touch the filename at all (in your example above, you added apostrophes around the filename).
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
是逃跑的输入,使输入将被壳为准确的一个字,这是等于输入
This is admittedly confusing. For a simple model, the whole point of pipes.quote
is to escape the input so that the input will be parsed by the shell as exactly one word, which is equal to the input.
下面是一个更一般正确的方式(并产生相同的结果):
The following is a more generally correct way (and yields the same result):
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)
据前presses更清晰的意图:准确控制外壳将解析什么话
It expresses more clearly the intent: Controlling what words exactly the shell will parse.
但是为什么在首位一个shell启动?我们不需要之一,可以保存在本地侧逸出。产卵的过程与我们的指定参数时,直接使用命令从 os.exec *
系列。
But why start with a shell in the first place? We don't need one and can save the escaping on the local side. To spawn a process with our args, directly, use commands from the os.exec*
family.
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)
这篇关于传递一个文件名以撇到SCP使用python的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!