上文書說到,ssh庫pexpect的使用,簡直就是個“月亮公主”——滿眼全是坑。勉強把程序寫好了,跑起來的時候發現了一個新坑,讓我不可抗拒的把它棄掉了——經常莫名其妙的連不上服務器!開線程連接14台服務器,總有1到3台連不上,還查不到原因。這還了得!一怒之下把寫好的pexpect封裝庫刪掉了,用paramiko重新寫起。其實這個庫也是有一些坑的,這個放在后面說。先介紹一下這個庫的用法。
安裝方法:沒有什么新鮮的
pip install paramiko
或者下載源碼編譯。需要事先安裝一下PyCrypto庫,同樣可以pip安裝。
使用方法:
import paramiko
之后,首先可以先建立一個全局的log(非必需)
paramiko.util.log_to_file('paramiko.log')
創建一個實例
s = paramiko.SSHClient()
設置一個balabala(好吧我解釋不清這是什么,密鑰之類的東西)
s.set_missing_host_key_policy(paramiko.AutoAddPolicy())
然后連接
s.connect(hostname=hostname, username=username, password=password)
注意連接方法並沒有返回值。
接下來發送一條命令
stdin, stdout, stderr = s.exec_command('ls -l')
paramiko所使用的shell是bash,即使在Ubuntu里面也沒有ll這個命令,只能用ls -l。
然后這里就有趣了。這里返回了三個流:stdin(標准輸入)、stdout(標准輸出)和strerr(標准錯誤),流是不可以直接讀的,得像打開一個文件那樣讀取,用read()或readlines()。並且,這兩個函數都是一次性的,也就是說,read()一次,再次read()時候結果為None,因此,需要有緩存來接住這個流:
sin, sout, serr = stdin.readlines(), stdout.readlines(), stderr.readlines()
read和readline的區別跟讀文件一樣,read是把所有值讀進一個字符串,自己處理;readlines是得到一個列表,按行分隔,可直接for i in out.readlines()也可以自己處理列表內容。
一般的情況,發送命令的返回結果都在out中,有這么幾種特殊情況:
1、執行錯誤。這時候out是一個空列表,而錯誤寫在了err中。
2、執行正確,但是本來命令就沒有什么返回值。這時候out和err都為空。
3、執行正確,但是由於某些特殊坑命令,返回值是在err中給出,out為空。
初次發現這個問題的時候我整個人是懵逼的,大概是這么個表情:
卧槽這特么要怎么判斷執行結果?后來想了些辦法,迂回來看了。比如wget就是這樣。解決方案是在命令結束后再發送一個ls命令,查看一下現在文件是否存在。
4、sudo命令。這特么就是個萬年大坑,不管是pexpect還是paramiko,我都栽在sudo上面好久。血淚史我就不說了,直接說解決方法吧:
首先,sudo后面要加一個-S選項,表示從標准輸入接收密碼。標准輸入?咋么聽起來那么耳熟?沒錯,就是stdin,發送完命令之后要再發個密碼;然后,命令的最后要加上’\n’作為命令的結束,如果沒有加,那么恭喜你,服務器以為你沒有結束命令,還在等待,而你不知道服務器的狀態,在等待它給你反饋。於是
“我的心,在等待,永遠在等待哎哎~~” “你知不知道,你知不知道,我等到花兒也謝了嗷嗷~~” “等下一個天亮,去上次牽手賞花那里散步好嗎~” 。。。。。。
咳咳,回來。總的來說sudo就是這樣的:
stdin, stdout, stderr = s.exec_command(‘sudo -S %s\n’ % cmd) stdin.write(‘%s\n’ % password) stdin.flush() out = stdout.readlines()
這樣就可以了。
最后的最后,別忘了退出
s.close()
我使用的就是這么多了。其他的有send和recv函數,可以跟pexpect一樣發送命令,接收命令;有RSA等加密方法;還有很多方便的函數。平胸而論,不對,平心而論,這個庫應該是蠻不錯的,可以做一個交互式的ssh shell,而且據說windows下也可以用,比pexpect不知道高到哪里去了。只是我時間太倉促,晚上加班幾個小時內學一個新庫,又把200多行代碼完全推倒重寫,任誰都會有點怨言是吧。以后如果需要的話(學乖了,不說有時間的話)還可以繼續深入研究一下。
這次就先到這里了。