2014-10-16 35 views
5

Ho uno script Python che uso per eseguire comandi in parallelo su più host usando il modulo subprocesso Python. Si avvolge SSH, e fondamentalmente fa una chiamata in questo modo:Terminale incasinato (non visualizzava nuove righe) dopo aver eseguito lo script Python

output = subprocess.Popen(["/bin/env", env, "/usr/bin/ssh", "-t", "%[email protected]%s" % (user, host), "--", command], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() 

Il comando effettivo viene eseguito in questo modo:

/bin/env TERM=$TERM:password /usr/bin/ssh -t "%[email protected]%s" % (user, host), "--", command 

Funziona bene, tranne che ottengo un errore intermittente in cui mio terminale viene incasinato (perde newline) dopo aver eseguito lo script. Un "reset" dalla riga di comando lo corregge, ma non sono sicuro di come ciò avvenga, esattamente. Ho notato che a volte c'è uno "\ r \ n" alla fine del primo elemento nell'output della tupla e talvolta non è lì. Vedere il seguente, in particolare "Permesso negato \ r \ n":

**** Okay output **** 
[[email protected]/home/user]# ./command.py hosts.lists "grep root /etc/shadow" 
Running command "grep root /etc/shadow" on hosts in file "hosts.test" 
('grep: /etc/shadow: Permission denied\r\n', 'Connection to server1.example.com closed.\r\n') 
('grep: /etc/shadow: Permission denied\r\n', 'Connection to server2.example.com closed.\r\n') 
[[email protected]/home/user]# 


**** Output causes terminal to not display newlines **** 
[[email protected]/home/user]# ./command.py hosts.list "grep root /etc/shadow" 
('grep: /etc/shadow: Permission denied\r\n', 'Connection to server1.example.com closed.\r\n') 
('grep: /etc/shadow: Permission denied\n', 'Connection to server2.example.com closed.\r\n') 
           [[email protected]/home/user]# [[email protected]/home/user]# [[email protected]/home/user] 

La seconda uscita è stata leggermente modificata, ma mostra dei dispersi "\ r", e come il mio sollecito ottiene "wacked" dopo aver eseguito lo script.

Penso che questo sia correlato all'utilizzo dell'opzione "-t" nel mio comando di sottoprocesso. In qualche modo sto perdendo il \ r. Se rimuovo l'opzione "-t", questo problema scompare, ma per farla breve, ne ho bisogno per passare attraverso le variabili ambientali per l'utilizzo sulla macchina remota (sto usando la variabile TERM per passare la password dell'utente per scopi sudo, perché non posso supporre che AcceptEnv consenta il passaggio di variabili arbitrarie sul server sshd remoto; lo sto facendo per evitare di passare la password sulla riga di comando, che verrà visualizzata nell'elenco dei processi sulla macchina remota).

Basta chiedersi se qualcuno conosce un modo per aggirare questo, senza rimuovere l'opzione "-t"?

UPDATE:. Sembra che le mie impostazioni TTY vengono modificate dopo l'esecuzione del subprocess.Popen (...) comunicare() comando all'interno mio script, indipendentemente dal fatto che ho effettivamente stampare l'output di schermo. Lo trovo davvero strano. Qui ci sono le prima/dopo differenze nella mia TTY config (da -a stty):

-ignbrk brkint ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff 
-ignbrk brkint ignpar -parmrk -inpck -istrip -inlcr -igncr -icrnl -ixon -ixoff 


opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0 
-opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0 

isig icanon -iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt 
-isig -icanon -iexten -echo -echoe -echok -echonl -noflsh -xcase -tostop -echoprt 

Mi chiedo come fermare comunicare() da alterare le impostazioni del terminale? È possibile o è un bug?

+0

il * comando * richiede effettivamente l'opzione '-t' ssh? – jfs

+0

'.communicate()' non modifica le tue impostazioni tty. Prova qualche maledetto script Python che non ripristini le sue impostazioni all'uscita come un * comando * e vedi se è possibile riprodurre l'errore in modo affidabile, ad esempio, fai in modo che lo script accetti un flag sull'opportunità di ripristinare tty all'uscita o meno. Ad esempio, – jfs

+0

, non si può fare nulla nel blocco 'finally' se viene passato un flag' --no-restore' in [questo script] (http://stackoverflow.com/a/327072/4279) – jfs

risposta

4

Ho avuto lo stesso problema in uno script Perl. Per risolvere il problema, ho dovuto salvare le impostazioni correnti del terminale locale (per ripristinarlo alla fine dello script) e anteporre "stty -raw" prima di eseguire il comando remoto.

Così in Perl:

impostazioni del terminale corrente #Save (si può aggiungere il PID nel nome del file)

`stty -g> ~/tmp/.currentTtySettings`;

comando remoto #Execute anteponendo "stty -raw"

mia @ out = `ssh -t -q [email protected] "stty -raw; grep root/etc/shadow" `;

impostazioni del terminale #Restore

`stty \` cat ~/tmp/.currentTtySettings \ ``;

Spero che ti aiuti!

Altri link molto utili:

-Detailed spiegazione ssh e TTY (opzione -t) https://unix.stackexchange.com/questions/151916/why-is-this-binary-file-being-changed

-Alcuni Perl e ssh ispirazione http://search.cpan.org/~bnegrao/Net-SSH-Expect-1.09/lib/Net/SSH/Expect.pod

-Come da evitare "-t" per sudo https://unix.stackexchange.com/questions/122616/why-do-i-need-a-tty-to-run-sudo-if-i-can-sudo-without-a-password

0

ho scoperto che

stty sane 

ripristina la console come era prima. Non ho davvero capito l'altra risposta qui, quindi questo aiuta qualcuno.

Trovato la risposta here.