【发布时间】:2018-03-20 23:12:58
【问题描述】:
我想写一个小脚本,用/usr/lib/w3mimgdisplay将图像打印到终端(就像在mac osx中lsi)。因此我需要脚本启动时的实际光标位置(或插入符号位置)。到目前为止,我想通过 ANSI 序列在 shell 中获取光标位置:
$ echo -en "\e[6n"
^[[2;1R$ 1R
这就是这个 ANSI 序列的响应的样子(urvxt 和 bash - 不知道这是否重要)。所以这个序列会立即打印出结果 (^[[2;1R)。这是我不明白的。这是怎么做到的?如果我编写了一个非常简单的 shell 脚本,只需使用该指令并 strace 脚本,这并不能解决问题。什么?然后我试图通过查看 terminfo 手册页来弄清楚这是如何发生的。在这里找不到(也许我不够努力)。在这一点上,我发现自己对这个概念非常困惑。终端是否将位置甚至写入标准输出?
终端
#!/bin/bash
echo -en "\e[6n"
$ strace sh curpos.sh
[...]
read(255, "#!/bin/bash\necho -en \"\\e[6n\"\n", 29) = 29
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 8), ...}) = 0
write(1, "\33[6n", 4) = 4
^[[54;21Rread(255, "", 29) = 0
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
exit_group(0) = ?
+++ exited with 0 +++
Python
首先我尝试使用subprocess.check_output,它当然只是返回我回显的字符串。如何捕获对这个 ANSI 序列的响应?
>>> subprocess.check_output(["echo", "-en", "\x1b[6n"])
b"\x1b[6n"
我还尝试了很多其他的东西,比如阅读标准输入和标准输出!?有和没有线程,但所有这些更多的是猜测和嘲笑,而不是知道该怎么做。我也在互联网上搜索了很长一段时间,希望找到一个如何做到这一点的例子,但没有运气。我找到了相同问题的答案:https://stackoverflow.com/a/35526389/2787738 但这不起作用。实际上我不知道这是否有效,因为在这个答案中,ANSI序列在开始从标准输入读取之前被写入标准输出?在这里,我再次意识到我不了解这些 ANSI 序列如何真正工作的概念/机制。因此,在这一点上,非常感谢每一个澄清问题的解释。我发现的最有帮助的帖子是这个:https://www.linuxquestions.org/questions/programming-9/get-cursor-position-in-c-947833/。在这个线程中,有人发布了这个 bash 脚本:
#!/bin/bash
# Restore terminal settings when the script exits.
termios="$(stty -g)"
trap "stty '$termios'" EXIT
# Disable ICANON ECHO. Should probably also disable CREAD.
stty -icanon -echo
# Request cursor coordinates
printf '\033[6n'
# Read response from standard input; note, it ends at R, not at newline
read -d "R" rowscols
# Clean up the rowscols (from \033[rows;cols -- the R at end was eaten)
rowscols="${rowscols//[^0-9;]/}"
rowscols=("${rowscols//;/ }")
printf '(row %d, column %d) ' ${rowscols[0]} ${rowscols[1]}
# Reset original terminal settings.
stty "$termios"
在这里我们可以看到,响应确实以某种方式神奇地出现在屏幕上:)。这就是为什么此脚本禁用终端上的回显并在读取响应后通过stty 重置原始终端设置的原因。
【问题讨论】:
-
看起来相关:远程终端将在该位置“键入”,就好像用户键入它一样。您需要实际发送它才能发生这种情况:stackoverflow.com/questions/8343250/…
-
@max 但是如何读取这个按键?
sys.stdin.read(),我猜。但是subprocess.check_output(["echo", "-en", "\x1b[6n"]);curpos=sys,stdin.read(10)不起作用。是因为竞争条件问题还是 python shell 以某种方式忽略了它?
标签: python python-3.x terminal ansi-escape