我試圖在遠程部署的嵌入式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嘗試,但等待用戶輸入?
謝謝!
謝謝,它不使用標準的標準輸入/輸出/標準錯誤的見解幫了不少忙。它看起來像「pexpect」可以正確地驅動scp,並且甚至還有一個用於paramiko的scp插件,可以將它帶入Python世界。 不幸的是,「pexpect」不能創建它所需要的虛擬pty,我沒有paramiko需要的密碼包的編譯版本。由於我正在開發第三方嵌入式設備,因此更改系統設置以允許創建pty或交叉編譯包是很困難的。 – digitalosmosis
@digitalosmosis增加了一個「裸骨」的例子,可以幫助你。 – mweerden