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

2

11

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?

Pecuniary answered 16/10, 2014 at 21:4 Comment(7)
does the command actually needs -t ssh option?Carnegie
.communicate() doesn't alter your tty settings. Try some curses Python script that doesn't restore its settings on exit as a command and see whether you can reproduce the error reliably i.e., make the script accept a flag on whether to restore tty on exit or not.Carnegie
for example, you could do nothing in the finally block if a --no-restore flag is passed in this scriptCarnegie
Yes, the command needs the "-t" option in order to pass through the local TERM variable, for something admittedly hackish I'm trying to do. If I capture and restore the tty settings before and after .communicate(), I can fix the shell following completion of the command. However, the output from my script gets very jumbled from all the extra spaces. In situations where I run this script against large numbers of machines (not just two), it becomes unreadable. I'm curious as to what's causing the extra output to my screen.Pecuniary
Have you tried to run the curses script?Carnegie
Not yet, I'll try that.Pecuniary
Calling .terminate() on output will fix the terminal after the script ended. So .terminate() is restoring it to the initial setting, but this is not a general solution to the problem.Protestantism
P
11

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.

Pleione answered 1/2, 2018 at 11:33 Comment(2)
At least it helps after the terminal got messed up.Protestantism
You can also try reset to get a similar result.Carotid
I
5

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

Insurmountable answered 12/12, 2014 at 21:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.