我想创建像git rebase -i HEAD~6
这样的交互模式代码,但用于PIPE编辑,stdin重定向。另一个例子是moreutils
的vipe。
为了做到这一点,我学习了下面的代码。
# 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])
为了获取PIPE并编辑它,我添加了两行。
text = sys.stdin.read()
initial_message = text.encode()
有问题的完整代码如下。
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])
在shell中使用echo "some words" | python the_code.py
运行第二段代码并退出vim :q!
后,终端就乱套了。(shell命令中的reset
将修复它。)
没有reset
,我可以输入macOS的shell,但提示符在一个奇怪的地方。我甚至不能输入Linux的shell。
- 我已经输入了
set -x
*
[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]$
我只是想返回正常终端后运行第二个完整的代码。还有,为什么会这样?
我在代码的最后尝试了os.system('stty sane; clear;')
和os.system('reset')
。(https://stackoverflow.com/a/17452756/20307768)os.system('reset')
给了我想要的。但是信息很烦人。我的意思是我可以再做一次os.system('clear')
,但这不是正常的其他程序所做的。
Erase set to delete.
Kill set to control-U (^U).
Interrupt set to control-C (^C).
1条答案
按热度按时间i2byvkas1#
我想创建交互模式的代码,如git rebase -i HEAD~6,但用于PIPE编辑,stdin重定向。另一个例子是Moreutils的VIPE。
vipe是一个开源工具,source code不到100行,所以让我们花点时间来看看它是如何做到这一点的。它不能依赖于stdin或stdout作为终端,因为通常它是在一系列管道的中间使用的。
这是他们如何解决的,在Perl中。首先,它们关闭STDIN,即文件描述符0。然后,它们在描述符0处以读取模式打开
/dev/tty
。他们也为STDOUT做同样的事情,但我们不需要。那么,我们如何在Python中做同样的事情呢?
1.在读取模式下打开
/dev/tty
。1.可能尚未在描述符0处打开,因此将其复制到描述符0。
1.关闭旧FD。
代码:
这是在OSX 13.3.1上测试的。