2012-11-07 29 views
4

我正在使用shlex使用subprocess.popen來使用ssh調用遠程bash腳本。這個命令在bash本身上工作得很好。但只要我嘗試用subprocess.popen將它翻譯成python和shlex,它就會錯誤地出現。使用Python通過ssh將文件捕獲到遠程bash腳本

遠程bash腳本:

#!/bin/bash 
tmp="";  
while read -r line; 
do 
    tmp="$tmp $line\n"; 
done; 
echo $tmp; 

BASH CMD RESULT(調用遠程bash腳本在命令行上)

$> ssh x.x.x.x cat < /tmp/bef69a1d-e580-5780-8963-6a9b950e529f.txt " | /path/to/bash/script.sh;" 
Bar\n 
$> 

Python代碼

import shlex 
import subprocess 

fn = '/tmp/bef69a1d-e580-5780-8963-6a9b950e529f.txt' 
s = """                  
ssh x.x.x.x cat < {localfile} '| /path/to/bash/script.sh;' 
""".format(localfile=fn) 

print s 

lexer = shlex.shlex(s)              
lexer.quotes = "'"               
lexer.whitespace_split = True            
sbash = list(lexer)               
print sbash                 

# print buildCmd               
proc=subprocess.Popen(sbash,stdout=subprocess.PIPE,stderr=subprocess.PIPE) 
out,err=proc.communicate()             

print "Out: " + out               
print "Err: " + err               

Python腳本結果

$> python rt.py 

    ssh x.x.x.x cat < /tmp/bef69a1d-e580-5780-8963-6a9b950e529f.txt '| /path/to/bash/script.sh' 
['ssh', 'x.x.x.x', 'cat', '<', '/tmp/bef69a1d-e580-5780-8963-6a9b950e529f.txt', "'| /path/to/bash/script.sh'"] 
Out: 
Err: bash: /tmp/bef69a1d-e580-5780-8963-6a9b950e529f.txt: No such file or directory 
$> 

我在想什麼?

+0

爲什麼你的python腳本在參數列表中有一個額外的''<'',看起來不存在於bash腳本中? (或者我讀錯了嗎?) – mgilson

+0

我錯過了,錯字。我通過將<放在bash命令行中來糾正它。 – Chris

+0

本地或遠程系統上是否有/ tmp/bef69a1d-e580-5780-8963-6a9b950e529f.txt文件?如果它是本地的,我想我會以不同的方式運行你的命令,例如'cat /tmp/bef69a1d-e580-5780-8963-6a9b950e529f.txt | ssh x.x.x.x/path/to/bash/script.sh'不需要在遠端運行cat。 (我不確定這是否會解決你的Python問題。) – Blckknght

回答

4

問題是您在命令中使用了shell重定向,但在使用子進程時沒有生成shell。

考慮以下(很簡單)程序:

import sys 
print sys.argv 

現在,如果我們運行它就像你正在運行ssh(假設foofile.txt存在),我們得到:

python argcheck.py ssh cat < foofile.txt " | /path/to/bash/script.sh;" 
['argcheck.py', 'ssh', 'cat', ' | /path/to/bash/script.sh;'] 

注意< foofile.txt永遠不要讓它成爲python的命令行參數。這是因爲bash解析器攔截了<及其之後的文件,並將該文件的內容重定向到程序的stdin。換句話說,ssh正在從stdin讀取文件。您希望使用python將您的文件傳遞給stdinssh

s = """                  
ssh x.x.x.x cat '| /path/to/bash/script.sh;' 
""" 

#<snip> 

proc=subprocess.Popen(sbash,stdout=subprocess.PIPE,stderr=subprocess.PIPE, 
          stdin=subprocess.PIPE) 
out,err=proc.communicate(open(fn).read()) 

將起作用。


對我來說,以下工作:

import subprocess 
from subprocess import PIPE 

with open('foo.h') as f: 
    p = subprocess.Popen(['ssh','[email protected]','cat','| cat'],stdin=f,stdout=PIPE,stderr=PIPE) 
    out,err = p.communicate() 
    print out 
    print '#'*80 
    print err 
bash

以及等效命令:

ssh [email protected] cat < foo.h '| cat' 

其中foo.h是我的本地機器上的文件。

+0

不錯,從來沒有想過使用communic()作爲我的標準輸入。我現在得到一個不同的錯誤 出: 錯誤:bash:cat | /path/to/bash/script.sh:沒有這樣的文件或目錄 似乎它正在我的本地機器上查找,並失敗。 – Chris

+0

@Chris - 我想你可以直接將打開的文件對象傳遞給'Popen'構造函數中的'stdin'。這可能是一個稍微乾淨一點的做法。 – mgilson

+0

同樣的事情。 錯誤:bash:cat | /path/to/bash/script.sh:沒有這樣的文件或目錄 – Chris

相關問題