2012-12-09 65 views
2

我想寫一個python腳本通過scp將文件從遠程服務器複製到本地目錄。傳遞一個帶有撇號的文件名到scp使用python

因爲我在OpenELEC發行版上運行它(最小的HTPC linux發行版,除userhome之外的只讀文件系統使安裝python ssh模塊變得不切實際),我這樣做很醜,只是將文件名傳遞給scp命令通過os.system。

SCPCopy = "scp -c blowfish -C [email protected]:\"" + pipes.quote(file) + "\" /storage/downloads/incoming/" 
SCPCopy = SCPCopy.replace('\n','') 
os.system(SCPCopy) 

這有效,除了包含撇號的文件名。

下面是什麼得到通過在一個文件中使用os.system用單引號的例子:

scp -c blowfish -C [email protected]:"'/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)並用/替換撇號,但是這並不能讓我獲得任何地方。

+0

Python文檔說'pipes.quote'從版本1.6開始已被棄用! –

+0

我試過不使用pipes.quote,只是用這樣的替換撇號:SCPCopy = SCPCopy.replace(「'」,「\'」) 但是,我得到了同樣的錯誤。 – evanjd

+0

使用'shlex.quote'並且不要使用你自己的'\''。 –

回答

6

由於scp基於SSH,你給它的文件名是受殼逸出在遠程的一面。因此你需要逃脫兩次。

一個正確轉義爲CMDLINE外殼:

scp -c blowfish -C [email protected]:"\"/media/sdi1/home/data/bob's file\"" /storage/.../ 

爲了使Python字符串,我們必須添加逃逸多了一個層次。如果你這樣做編程

"""scp -c blowfish -C [email protected]:"\"/media/sdi1/home/data/bob's file\"" /storage/.../""" 

(例如,使用過時的pipes.quote),那麼就不要碰在所有的文件名(在你上面的例子,你周圍添加引號:要保持清醒,我們可以用三引號文件名)。

fp = "/media/sdi1/home/data/bob's file.avi" 
fp = "[email protected]:" + 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", "[email protected]:"+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呢?我們不需要一個,可以在本地保存逃跑。爲了用我們的參數產生一個進程,直接使用os.exec*系列的命令。

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

太好了,謝謝 - 這很有效。 我必須將用戶@主機移動到cmdline字符串,因爲pipes.quote向用戶名添加了撇號。 編輯:只注意到你的更新 - 非常豐富,謝謝! – evanjd

相關問題