scp 功能很強大,但需要人工輸入 password, 當然可以通過把 公鑰保存在遠程主機的 ~/.ssh 目錄中,而后就不用輸入password,但這需要配置.
用 sshpass 可能在命令輸入 password, 但 需要用 “sudo apt-get install sshpass” 安裝
如果不想用上面兩種方法,可以用 expect 編寫腳本可以幫助我們自動交互
雖然 python 也提供?pexpect ?模塊,但既然 expect 很簡單,為何不直接用 os.system() 去執行呢?
下面是我編寫的類,實現了遠程復制?
[html] view plaincopyprint?
class?RemoteShell:????????def?__init__(self,?host,?user,?pwd):??????????self.host?=?host??????????self.user??=?user??????????self.pwd??=?pwd??????????def?put(self,?local_path,?remote_path):??scp_put?=?'''??spawn?scp?%s?%s@%s:%s??expect?"(yes/no)?"?{??send?"yes\r"??expect?"password:"??send?"%s\r"??}?"password:"?{send?"%s\r"}??expect?eof??exit'''??????????os.system("echo?'%s'?>?scp_put.cmd"?%?(scp_put?%?(os.path.expanduser(local_path),?self.user,?self.host,?remote_path,?self.pwd,?self.pwd)))??????????os.system('expect?scp_put.cmd')??????????os.system('rm?scp_put.cmd')??
class RemoteShell:def __init__(self, host, user, pwd):self.host = hostself.user = userself.pwd = pwddef put(self, local_path, remote_path):
scp_put = '''
spawn scp %s %s@%s:%s
expect "(yes/no)?" {
send "yes\r"
expect "password:"
send "%s\r"
} "password:" {send "%s\r"}
expect eof
exit'''os.system("echo '%s' > scp_put.cmd" % (scp_put % (os.path.expanduser(local_path), self.user, self.host, remote_path, self.pwd, self.pwd)))os.system('expect scp_put.cmd')os.system('rm scp_put.cmd')
但發現每次文件都沒有復制完,我想看expect 究竟做了什么事情,還好 expect 提供 -d 參數給出更多的信息。
最后發現是被復制文件太大,expect 超時退出了
在腳本前加入 “set timeout -1" 就OK了
[html] view plaincopyprint?
scp_put?=?'''??set?timeout?-1??spawn?scp?%s?%s@%s:%s??expect?"(yes/no)?"?{??send?"yes\r"??expect?"password:"??send?"%s\r"??}?"password:"?{send?"%s\r"}??expect?eof??exit'''??
scp_put = '''
set timeout -1
spawn scp %s %s@%s:%s
expect "(yes/no)?" {
send "yes\r"
expect "password:"
send "%s\r"
} "password:" {send "%s\r"}
expect eof
exit'''
總結
1) expect 每一條語句都是順序執行
[html] view plaincopyprint?
??
</pre>?因為scp 可能先返回 (yes/no)? 再 返回 password:, 也可能直接返回password:, 考慮順序關系,上面語句的層次關系其實如下: <div class="dp-highlighter bg_html"><div class="bar"><div class="tools"><strong>[html]</strong> <a target=_blank title="view plain" class="ViewSource" href="http://blog.csdn.net/span76/article/details/11575231#">view plain</a><a target=_blank title="copy" class="CopyToClipboard" href="http://blog.csdn.net/span76/article/details/11575231#">copy</a><a target=_blank title="print" class="PrintSource" href="http://blog.csdn.net/span76/article/details/11575231#">print</a><a target=_blank title="?" class="About" href="http://blog.csdn.net/span76/article/details/11575231#">?</a></div></div><ol class="dp-xml"><li class="alt"><span><span>expect?"(yes/no)?"?{???send?"yes\r"??</span></span></li><li><span>???????????????????????expect?"password:"??</span></li><li class="alt"><span>???????????????????????send?"%s\r"??</span></li><li><span>????????????????????}???</span></li><li class="alt"><span>???????"password:"?{send?"%s\r"}??</span></li></ol></div><pre class="html" style="display: none;" name="code">expect "(yes/no)?" { send "yes\r"expect "password:"send "%s\r"} "password:" {send "%s\r"}
2) 每當 spawn 的程序有輸出的時候的,expect都會去匹配, 如果匹配不上,就等下次有輸出,再次執行當前的 expect, 直到超時 (我用 expect -d 去追蹤,得到的結論);當然可以設置沒有超時 "set timeout -1"
3) 如果 ?expect 退出, 被它 spawn 的程序會被 kill 掉
4) spawn 結束的時候,它向標準輸出的的 eof 會被 expect 檢測到,正好作為 expect 腳本退出的時機。
對于 scp 可以先檢測 100%,因為 scp 會輸出復制進度,再檢測 eof
[html] view plaincopyprint?
expect?"100%%"??expect?eof??
expect "100%%"
expect eof
5) expect 是部分匹配,所以不要擔心自己不知道程序的完整輸出
版權聲明:本文為博主原創文章,未經博主允許不得轉載。
總結
以上是生活随笔為你收集整理的用python实现远程复制 (scp + expect )的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。