2

私は、scpを介してリモートサーバーからローカルディレクトリにファイルをコピーするPythonスクリプトを作成しようとしています。

これを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)

これは、アポストロフィを含むファイル名を除いて機能します。

以下は、アポストロフィを含むファイルで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

pipes.quote(x)がアポストロフィをエスケープしているように見えますが(必要に応じて)、構文がまだ正しくないことは明らかです。私はpipes.quote(x)を捨てて、アポストロフィを/'に置き換えることを実験しましたが、それでもどこにも行き着きません。

4

1 に答える 1

6

scpに基づいているためSSH、指定したファイル名は、リモート側でもシェル エスケープの対象となります。したがって、2 回エスケープする必要があります。

シェルの正しくエスケープされたコマンドライン:

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

Python 文字列を作成するには、もう 1 レベルのエスケープを追加する必要があります。正気を保つために、三重引用符を使用できます。

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

プログラムで(たとえば、 deprecated を使用して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入力をエスケープして、入力がシェルによって正確に1 つの wordとして解析されるようにすることです。これはinput と同じです。

以下は、より一般的に正しい方法です (同じ結果が得られます)。

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)

意図をより明確に表現します。シェルが解析する単語を正確に制御します。

しかし、そもそもなぜシェルから始めるのでしょうか? これは必要なく、ローカル側でエスケープを保存できます。引数を使用してプロセスを直接生成するには、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)
于 2012-12-09T04:26:51.737 に答える