Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Terminal messed up (not displaying new lines) after running Python script

I have a Python script I use to execute commands in parallel across multiple hosts using the Python subprocess module. It wraps SSH, and basically makes a call like this:

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

The effective command gets executed like this:

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

It works fine, except I get an intermittent error where my terminal gets messed up (loses newlines) after running the script. A "reset" from the command line fixes it, but I'm not sure how this is happening, exactly. I noticed that sometimes there's a "\r\n" at the end of the the first item in the tuple's output, and sometimes it's not there. See the following, specifically "Permission denied\r\n":

**** Okay output ****
[user@/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')
[user@/home/user]#


**** Output causes terminal to not display newlines ****
[user@/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')
                                 [user@/home/user]# [user@/home/user]# [user@/home/user]

The second output has been slightly modified, but shows the missing "\r", and how my prompt gets "wacked" after running the script.

I think this is related to using the "-t" option in my subprocess command. Somehow I'm losing the \r. If I remove the "-t" option, this issue goes away, but long story short, I need it for passing through environmental variables for use on the remote machine (I'm hackishly using the TERM variable to pass through the user's password for sudo purposes, because I can't assume AcceptEnv is allowing arbitrary variable passing on the remote sshd server; I'm doing this to avoid passing the password on the command line, which will show up in the process list on the remote machine).

Just wondering if anyone knows a way to get around this, without removing the "-t" option?

UPDATE: It looks like my tty settings get altered after running the subprocess.Popen(...).communicate() command within my script, regardless of whether or not I actually print the output to screen. I find that really strange. Here are the before/after differences in my tty config (from stty -a):

-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

I'm wondering how to stop communicate() from altering my terminal settings? Is it possible, or is this a bug?

like image 862
blindsnowmobile Avatar asked Oct 16 '14 21:10

blindsnowmobile


People also ask

How do you newline in Python terminal?

The new line character in Python is \n . It is used to indicate the end of a line of text. You can print strings without adding a new line with end = <character> , which <character> is the character that will be used to separate the lines.

What happens when you type Python in terminal?

when you type python on terminal or command prompt then it will open python interpreter in interactive mode.

How do I start a new line in IDLE?

Use the Ctrl - J key sequence instead of the Enter key to get a plain newline plus indentation without having IDLE start interpreting your code. You can find other key sequences that make IDLE easier to use for this type of learning under the Options->Configure IDLE menu.

How do you run multiple lines in Python?

How to Execute Multiple Lines in a Single Line Python From Command-Line? Summary: To make a Python one-liner out of any multi-line Python script, replace the new lines with a new line character '\n' and pass the result into the exec(...) function.


2 Answers

I found that

stty sane

restores the console to how it was before. I didn't really understand the other answer here so I this helps someone.

Found the answer here.

like image 110
jhylands Avatar answered Nov 15 '22 14:11

jhylands


I had the same issue in a Perl script. To solve the problem I had to save the current settings of the local terminal (in order to restore it at the end of the script) and prepending "stty -raw" before executing the remote command.

So in Perl:

#Save current terminal settings (you may add the PID in the filename)

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

#Execute remote command prepending "stty -raw"

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

#Restore terminal settings

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

Hope it helps you!

Other very useful links:

-Detailed explanation of ssh and tty (-t option) https://unix.stackexchange.com/questions/151916/why-is-this-binary-file-being-changed

-Some Perl and ssh inspiration http://search.cpan.org/~bnegrao/Net-SSH-Expect-1.09/lib/Net/SSH/Expect.pod

-How to avoid "-t" for sudo https://unix.stackexchange.com/questions/122616/why-do-i-need-a-tty-to-run-sudo-if-i-can-sudo-without-a-password

like image 30
Lennon Machado Avatar answered Nov 15 '22 12:11

Lennon Machado