英文:
How not to mess terminal up after sys.stdin.read() and subprocess invoking vim?
问题
以下是您要翻译的内容:
I want to create interactive mode code like git rebase -i HEAD~6
but for PIPE editing, stdin redirection. another example is vipe of moreutils
.
To do that, I learn this code below.
# Source: https://stackoverflow.com/a/39989442/20307768
import sys, tempfile, os
from subprocess import call
EDITOR = os.environ.get('EDITOR', 'vim') # that easy!
initial_message = b'something' # if you want to set up the file somehow
with tempfile.NamedTemporaryFile(suffix=".tmp") as tf:
tf.write(initial_message)
tf.flush()
call([EDITOR, tf.name])
To get PIPE and edit it, I added two lines.
text = sys.stdin.read()
initial_message = text.encode()
The problematic full code is below.
import sys, tempfile, os
from subprocess import call
EDITOR = os.environ.get('EDITOR', 'vim')
text = sys.stdin.read()
initial_message = text.encode()
with tempfile.NamedTemporaryFile(suffix=".tmp") as tf:
tf.write(initial_message)
tf.flush()
call([EDITOR, tf.name])
After running the second code with echo "some words" | python the_code.py
in the shell and exiting vim:q!
, the terminal is messed up. (reset
in the shell command will fix it.)
Without reset
, I can type in a shell of macOS, but the prompt is in a weird place.
I can't even type in a shell of Linux.
I typed set -x
, already.
[rockyos@localhost python-vipe]$ echo "asdfasd" | python vipe.py
+ python vipe.py
+ echo asdfasd
Vim: Warning: Input is not from a terminal
++ printf '3]0;%s@%s:%s[rockyos@localhost python-vipe]$ echo "asdfasd" | python vipe.py
+ python vipe.py
+ echo asdfasd
Vim: Warning: Input is not from a terminal
++ printf '\033]0;%s@%s:%s\007' rockyos localhost '~/TODO/python-vipe'
++ history -a
++ history -c
++ history -r
[rockyos@localhost python-vipe]$
7' rockyos localhost '~/TODO/python-vipe'
++ history -a
++ history -c
++ history -r
[rockyos@localhost python-vipe]$
I just want to return normal terminal after running the second full code.
Also, why is this happening?
I tried os.system('stty sane; clear;')
and os.system('reset')
at the end of the code. (os.system('reset')
gave me what I wanted. But the message is annoying. I mean I can do os.system('clear')
again, but that is not what normal other program does.
Erase set to delete.
Kill set to control-U (^U).
Interrupt set to control-C (^C).
英文:
I want to create interactive mode code like git rebase -i HEAD~6
but for PIPE editing, stdin redirection. another example is vipe of moreutils
.
To do that, I learn this code below.
# Source: https://stackoverflow.com/a/39989442/20307768
import sys, tempfile, os
from subprocess import call
EDITOR = os.environ.get('EDITOR', 'vim') # that easy!
initial_message = b'something' # if you want to set up the file somehow
with tempfile.NamedTemporaryFile(suffix=".tmp") as tf:
tf.write(initial_message)
tf.flush()
call([EDITOR, tf.name])
To get PIPE and edit it, I added two lines.
text = sys.stdin.read()
initial_message = text.encode()
The problematic full code is below.
import sys, tempfile, os
from subprocess import call
EDITOR = os.environ.get('EDITOR', 'vim')
text = sys.stdin.read()
initial_message = text.encode()
with tempfile.NamedTemporaryFile(suffix=".tmp") as tf:
tf.write(initial_message)
tf.flush()
call([EDITOR, tf.name])
After running the second code with echo "some words" | python the_code.py
in the shell and exiting vim:q!
, the terminal is messed up. (reset
in the shell command will fix it.)
Without reset
, I can type in a shell of macOS, but the prompt is in a weird place.
I can't even type in a shell of Linux.
I typed set -x
, already.
[rockyos@localhost python-vipe]$ echo "asdfasd" | python vipe.py
+ python vipe.py
+ echo asdfasd
Vim: Warning: Input is not from a terminal
++ printf '3]0;%s@%s:%s[rockyos@localhost python-vipe]$ echo "asdfasd" | python vipe.py
+ python vipe.py
+ echo asdfasd
Vim: Warning: Input is not from a terminal
++ printf '\033]0;%s@%s:%s\007' rockyos localhost '~/TODO/python-vipe'
++ history -a
++ history -c
++ history -r
[rockyos@localhost python-vipe]$
7' rockyos localhost '~/TODO/python-vipe'
++ history -a
++ history -c
++ history -r
[rockyos@localhost python-vipe]$
I just want to return normal terminal after running the second full code.
Also, why is this happening?
I tried os.system('stty sane; clear;')
and os.system('reset')
at the end of the code.(https://stackoverflow.com/a/17452756/20307768) os.system('reset')
gave me what I wanted. But the message is annoying. I mean I can do os.system('clear')
again, but that is not what normal other program does.
Erase set to delete.
Kill set to control-U (^U).
Interrupt set to control-C (^C).
答案1
得分: 3
import sys, tempfile, os
from subprocess import check_call
EDITOR = os.environ.get('EDITOR', 'vim')
text = sys.stdin.read()
initial_message = text.encode()
with tempfile.NamedTemporaryFile(suffix=".tmp") as tf:
tf.write(initial_message)
tf.flush()
stdin_fd = os.open('/dev/tty', os.O_RDONLY)
os.dup2(stdin_fd, 0)
os.close(stdin_fd)
check_call([EDITOR, tf.name])
print(open(tf.name).read())
英文:
>I want to create interactive mode code like git rebase -i HEAD~6 but for PIPE editing, stdin redirection. another example is vipe of moreutils.
vipe is an open-source tool, and the source code is less than 100 lines long, so let's take a moment to look at how it does this. It can't rely on stdin or stdout to be a terminal, because normally it's used in the middle of a series of pipes.
Here's how they solved that, in Perl. First, they close STDIN, or file descriptor 0. Then, they open /dev/tty
in read mode at descriptor 0. They also do the same thing for STDOUT, but we don't need that.
close STDIN;
open(STDIN, "</dev/tty") || die "reopen stdin: $!";
open(OUT, ">&STDOUT") || die "save stdout: $!";
close STDOUT;
open(STDOUT, ">/dev/tty") || die "reopen stdout: $!";
So, how can we do the same thing in Python?
- Open
/dev/tty
in read mode. - That might not have been opened at descriptor 0, so copy it to descriptor 0.
- Close the old FD.
Code:
import sys, tempfile, os
from subprocess import check_call
EDITOR = os.environ.get('EDITOR', 'vim')
text = sys.stdin.read()
initial_message = text.encode()
with tempfile.NamedTemporaryFile(suffix=".tmp") as tf:
tf.write(initial_message)
tf.flush()
stdin_fd = os.open('/dev/tty', os.O_RDONLY)
os.dup2(stdin_fd, 0)
os.close(stdin_fd)
check_call([EDITOR, tf.name])
print(open(tf.name).read())
This was tested on OSX 13.3.1.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论