运行 Python 脚本后终端混乱(不显示新行)
Posted
技术标签:
【中文标题】运行 Python 脚本后终端混乱(不显示新行)【英文标题】:Terminal messed up (not displaying new lines) after running Python script 【发布时间】:2014-12-12 09:03:48 【问题描述】:我有一个 Python 脚本,用于使用 Python 子进程模块跨多个主机并行执行命令。它包装了 SSH,基本上是这样调用的:
output = subprocess.Popen(["/bin/env", env, "/usr/bin/ssh", "-t", "%s@%s" % (user, host), "--", command], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
有效的命令是这样执行的:
/bin/env TERM=$TERM:password /usr/bin/ssh -t "%s@%s" % (user, host), "--", command
它工作正常,除了在运行脚本后我的终端出现混乱(丢失换行符)时出现间歇性错误。命令行中的“重置”可以修复它,但我不确定这是如何发生的。我注意到有时在元组输出的第一个项目的末尾有一个 "\r\n" ,有时它不存在。请参阅以下内容,特别是“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]
第二个输出稍作修改,但显示了缺少的 "\r",以及在运行脚本后我的提示是如何“变坏”的。
我认为这与在我的子进程命令中使用“-t”选项有关。不知何故,我失去了 \r。如果我删除“-t”选项,这个问题就会消失,但长话短说,我需要它来传递环境变量以在远程机器上使用(我正在使用 TERM 变量来传递用户的密码sudo 的目的,因为我不能假设 AcceptEnv 允许在远程 sshd 服务器上传递任意变量;我这样做是为了避免在命令行上传递密码,这将显示在远程机器上的进程列表中)。
只是想知道是否有人知道在不删除“-t”选项的情况下解决此问题的方法?
更新: 在我的脚本中运行 subprocess.Popen(...).communicate() 命令后,无论我是否实际将输出打印到屏幕,看起来我的 tty 设置都发生了变化。我觉得这真的很奇怪。以下是我的 tty 配置中的前后差异(来自 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
我想知道如何阻止communicate() 更改我的终端设置?有可能吗,或者这是一个错误?
【问题讨论】:
命令真的需要-t
ssh选项吗?
.communicate()
不会改变您的 tty 设置。尝试一些不会在退出时将其设置恢复为 command 的 curses Python 脚本,看看您是否可以可靠地重现错误,即,使脚本接受一个关于是否在退出时恢复 tty 的标志.
例如,如果--no-restore
标志在this script 中传递,您可以在finally
块中什么都不做
是的,该命令需要“-t”选项才能通过本地 TERM 变量,因为我正在尝试做一些公认的骇人听闻的事情。如果我在 .communicate() 之前和之后捕获并恢复 tty 设置,我可以在命令完成后修复 shell。但是,我的脚本的输出因所有额外的空格而变得非常混乱。在我对大量机器(不仅仅是两台)运行此脚本的情况下,它变得不可读。我很好奇是什么导致我的屏幕有额外的输出。
你试过运行 curses 脚本吗?
【参考方案1】:
我发现了
stty sane
将控制台恢复到以前的状态。 我真的不明白这里的其他答案,所以我这对某人有帮助。
找到答案here。
【讨论】:
至少在终端出现问题后会有所帮助。【参考方案2】:我在 Perl 脚本中遇到了同样的问题。为了解决这个问题,我必须保存本地终端的当前设置(以便在脚本末尾恢复它)并在执行远程命令之前添加“stty -raw”。
所以在 Perl 中:
#保存当前终端设置(可以在文件名中添加PID)
`stty -g > ~/tmp/.currentTtySettings`;
#Execute远程命令前置“stty -raw”
我的@out=`ssh -t -q user@server1.example.com "stty -raw ; grep root /etc/shadow"`;
#恢复终端设置
`stty \`cat ~/tmp/.currentTtySettings\``;
希望对你有帮助!
其他非常有用的链接:
-ssh和tty详解(-t选项)https://unix.stackexchange.com/questions/151916/why-is-this-binary-file-being-changed
-一些 Perl 和 ssh 的灵感http://search.cpan.org/~bnegrao/Net-SSH-Expect-1.09/lib/Net/SSH/Expect.pod
-如何避免 sudo https://unix.stackexchange.com/questions/122616/why-do-i-need-a-tty-to-run-sudo-if-i-can-sudo-without-a-password 出现“-t”
【讨论】:
以上是关于运行 Python 脚本后终端混乱(不显示新行)的主要内容,如果未能解决你的问题,请参考以下文章
在 Linux 上的终端启动时运行 python 脚本[关闭]
linux脚本里运行环境变量,不重启终端,重新登陆用户,让其一直有效,在脚本退出后,能被其他程序访问