2016-08-12 31 views
0

我試圖在遠程部署的嵌入式Linux設備上獲取python腳本來執行scp命令。執行該命令很簡單,但如果目標服務器未在'known_hosts'文件中列出,則scp會引發需要與之交互的警告。幾天來,我的頭反對這一點,我無法解決2個問題。Python - 處理子進程中的輸入提示

首先,我無法從子流程中獲取非阻塞讀取的響應,以正常工作。在下面的代碼中,即使當我知道我可以從stderr讀取(假設生成了可信主機文件警告)時,始終選擇始終返回([],[],[])。

cmdString = 'scp [email protected]:file localFile -i ~/.ssh/id_rsa' 

process = subprocess.Popen(shlex.split(cmdString), shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 

while(process.poll() is None): 
    readable, writable, exceptional = select.select([process.stdout], [], [process.stderr], 1) 

    if not (readable or writable or exceptional): 
    # Always hits this condition, although adding an "os.read(...)" here 
    # will return the error prompt from process.stderr. 
    print "timeout condition" 
    else: 
    # Never makes it here 
    for e in exceptional: 
     stderr = os.read(process.stderr.fileno(), 256) 
     print stderr 
    for r in readable: 
     stdout = os.read(process.stdout.fileno(), 256) 
     print stdout 

其次,我無法通過輸入管道輸入輸入來使子進程超出警告範圍。以下代碼讀取來自process.stderr的警告代碼,但之後會掛起,直到我在終端中點擊{enter}。我嘗試發送「n」,「n \ n」和「\ n」,但沒有任何一個會導致子進程繼續執行(儘管手動輸入時全部3種模式都有效)。

cmdString = 'scp [email protected]:file localFile -i ~/.ssh/id_rsa' 

process = subprocess.Popen(shlex.split(cmdString), shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 

# Correctly grabs warning and displays it 
stderr = os.read(process.stderr.fileno(), 256) 
print stderr 

# Just in case there was some weird race condition or something 
time.sleep(0.5) 

# Doesn't ever seem to do anything 
process.stdin.write('\n') 

最後,重要嗎?我最初開始調查子進程和PIPES,因爲我使用「os.system(cmdString)」來運行scp,它阻塞了我的線程並迫使我處理這個問題。現在我正在使用子進程,只是啓動命令並讓它成功或失敗,這不好嗎?失敗的子進程最終是否會終止,或者最終我會在哪裏運行數十或數百個隱藏的scp嘗試,但等待用戶輸入?

謝謝!

回答

0

在這種情況下,問題可能是scp不使用stdin/stdout/stderr進行通信,而是直接通過終端進行通信。

你可以通過在stackoverflow上搜索諸如scp input之類的東西來找到很多類似的問題以及處理它的方法。

只有父母「輸送」輸出(stdout/stderr)並且子進程試圖寫入內容時,啓動的子進程纔會死亡。在這種情況下,scp可能會繼續運行,因爲它使用的是終端。儘管這些過程並不真正隱藏,你可以用ps這樣的工具輕鬆看到它們(並用killkillall將它們殺死)。

編輯:正如你所說,你有各種庫的問題,也許下面的方法將幫助:

import os, pty 

pid, fd = pty.fork() 
if pid == 0: 
    os.execvp('scp', ['scp', '[email protected]:file', ... ]) 
else: 
    while True: 
    s = os.read(fd, 1024) 
    print repr(s) 
    os.write(fd, 'something\n') 
+0

謝謝,它不使用標準的標準輸入/輸出/標準錯誤的見解幫了不少忙。它看起來像「pexpect」可以正確地驅動scp,並且甚至還有一個用於paramiko的scp插件,可以將它帶入Python世界。 不幸的是,「pexpect」不能創建它所需要的虛擬pty,我沒有paramiko需要的密碼包的編譯版本。由於我正在開發第三方嵌入式設備,因此更改系統設置以允許創建pty或交叉編譯包是很困難的。 – digitalosmosis

+0

@digitalosmosis增加了一個「裸骨」的例子,可以幫助你。 – mweerden