2013-03-01 198 views
9

我試圖運行使用subprocess.Popenscp(安全複製)命令。登錄需要我發送密碼:發送過SSH或SCP密碼與subprocess.Popen

from subprocess import Popen, PIPE 

proc = Popen(['scp', "[email protected]:/foo/bar/somefile.txt", "."], stdin = PIPE) 
proc.stdin.write(b'mypassword') 
proc.stdin.flush() 

這立即返回一個錯誤:

[email protected]'s password: 
Permission denied, please try again. 

一定密碼是正確的。我可以通過在shell上手動調用scp來輕鬆驗證它。那麼爲什麼這不起作用呢?

注意,有很多類似的問題,這一點,詢問subprocess.Popen和自動化SSH或FTP登錄發送一個密碼:

How can I set a users password in linux from a python script?
Use subprocess to send a password

答案(S)對這些問題不要」牛逼的工作和/或因爲我使用Python 3

+0

我不熟悉這個代碼,但您嘗試使用-p參數?也作爲驗證方法的密鑰交換? – diego2k 2013-03-01 21:16:11

+0

With -pi mean「-p mypassword [email protected]:/foo/bar/somefile.txt」我不知道你是否可以這樣做 – diego2k 2013-03-01 21:16:55

+1

@ diego2k據我所知,scp不接受切換通過命令行輸入密碼(其手冊頁不包含此類內容)。一般來說它不是在命令行上提供密碼很好的做法,因爲這會被記錄下來在.bash_history的 – entropy 2013-03-01 21:25:39

回答

6

您所連結的第二個答案建議你使用Pexpect的(通常是去了解與期望輸入命令行程序進行交互以正確的方式)不適用。它有一個fork它適用於你可以使用的python3。

+1

注意:普通[pexpect](https://pypi.python.org/pypi/pexpect)現在支持Python 3。 – jfs 2014-08-06 12:47:44

9

這裏是一個功能ssh使用pexpect密碼:

def ssh(host, cmd, user, password, timeout=30, bg_run=False):                         
    """SSH'es to a host using the supplied credentials and executes a command.                         
    Throws an exception if the command doesn't return 0.                              
    bgrun: run command in the background"""                                  

    fname = tempfile.mktemp()                                     
    fout = open(fname, 'w')                                      

    options = '-q -oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null -oPubkeyAuthentication=no'                   
    if bg_run:                                       
     options += ' -f'                                      
    ssh_cmd = 'ssh %[email protected]%s %s "%s"' % (user, host, options, cmd)                             
    child = pexpect.spawn(ssh_cmd, timeout=timeout)                                
    child.expect(['password: '])                                                                        
    child.sendline(password)                                     
    child.logfile = fout                                      
    child.expect(pexpect.EOF)                                     
    child.close()                                        
    fout.close()                                        

    fin = open(fname, 'r')                                      
    stdout = fin.read()                                       
    fin.close()                                         

    if 0 != child.exitstatus:                                     
     raise Exception(stdout)                                     

    return stdout 

類似的東西應該使用scp是可能的。

+0

謝謝。這幫了我。我正在查找它,但是你能告訴我這一行是什麼意思嗎? '-q -oStrictHostKeyChecking = no -oUserKnownHostsFile =/dev/null -oPubkeyAuthentication = no' – alfonso 2015-12-05 17:12:55

+1

@alfonso這些都是你可以在命令行或者你的'.ssh/config'中傳遞給ssh的選項, O'。第一個告訴ssh不要抱怨,如果主機已經改變了它的關鍵因子,它可能已被重新安裝,因爲你上次使用這個。第二個說使用/ dev/null而不是.ssh/known_hosts,所以它會停止它抱怨,如果它已經重新安裝重複條目警告。最後幾天不使用強制密碼輸入的密鑰。 – sjbx 2015-12-06 07:18:49

4

Pexpect的具有正是這種庫:pxssh

http://pexpect.readthedocs.org/en/stable/api/pxssh.html

import pxssh 
import getpass 
try: 
    s = pxssh.pxssh() 
    hostname = raw_input('hostname: ') 
    username = raw_input('username: ') 
    password = getpass.getpass('password: ') 
    s.login(hostname, username, password) 
    s.sendline('uptime') # run a command 
    s.prompt()    # match the prompt 
    print(s.before)  # print everything before the prompt. 
    s.logout() 
except pxssh.ExceptionPxssh as e: 
    print("pxssh failed on login.") 
    print(e) 
1

我猜有些應用程序中使用標準輸入與用戶交互和一些應用程序使用終端進行交互。在這種情況下,當我們使用PIPE編寫密碼時,我們正在寫入stdin。但SCP應用程序從終端讀取密碼。由於子進程無法與使用終端的用戶交互,但只能使用stdin進行交互,所以我們不能使用子進程模塊,我們必須使用pexpect來使用scp來複制文件。

請隨時更正。