bash 如何在bash中获取光标位置?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2575037/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to get the cursor position in bash?
提问by nicoulaj
In a bash script, I want to get the cursor column in a variable. It looks like using the ANSI escape code {ESC}[6n
is the only way to get it, for example the following way:
在 bash 脚本中,我想在变量中获取光标列。看起来使用ANSI转义码{ESC}[6n
是获得它的唯一方法,例如以下方式:
# Query the cursor position
echo -en '3[6n'
# Read it to a variable
read -d R CURCOL
# Extract the column from the variable
CURCOL="${CURCOL##*;}"
# We have the column in the variable
echo $CURCOL
Unfortunately, this prints characters to the standard output and I want to do it silently. Besides, this is not very portable...
不幸的是,这会将字符打印到标准输出,我想默默地做。此外,这不是很便携......
Is there a pure-bash way to achieve this ?
有没有一种纯粹的 bash 方法来实现这一目标?
回答by Paused until further notice.
You have to resort to dirty tricks:
你必须诉诸肮脏的把戏:
#!/bin/bash
# based on a script from http://invisible-island.net/xterm/xterm.faq.html
exec < /dev/tty
oldstty=$(stty -g)
stty raw -echo min 0
# on my system, the following line can be replaced by the line below it
echo -en "3[6n" > /dev/tty
# tput u7 > /dev/tty # when TERM=xterm (and relatives)
IFS=';' read -r -d R -a pos
stty $oldstty
# change from one-based to zero based so they work with: tput cup $row $col
row=$((${pos[0]:2} - 1)) # strip off the esc-[
col=$((${pos[1]} - 1))
回答by BSK
You could tell read
to work silently with the -s
flag:
您可以告诉read
与-s
标志静默工作:
echo -en "\E[6n"
read -sdR CURPOS
CURPOS=${CURPOS#*[}
And then CURPOS is equal to something like 21;3
.
然后 CURPOS 等于21;3
.
回答by F. Hauri
My (two) version of same...
我的(两个)版本相同...
As a function, setting specific variable, using ncurses's user definedcomands:
作为函数,使用 ncurses 的用户定义命令设置特定变量:
getCPos () {
local v=() t=$(stty -g)
stty -echo
tput u7
IFS='[;' read -rd R -a v
stty $t
CPos=(${v[@]:1})
}
Than now:
比现在:
getCPos
echo $CPos
21
echo ${CPos[1]}
1
echo ${CPos[@]}
21 1
declare -p CPos
declare -a CPos=([0]="48" [1]="1")
Nota:I use ncurses
command: tput u7
at line #4
in the hope this will stay more portablethan using VT220
string by command: printf "\033[6n"
... Not sure: anyway this will work with any of them:
注意:我使用ncurses
command: tput u7
at line#4
希望这比使用string by command更便携VT220
:printf "\033[6n"
...不确定:无论如何这将适用于其中任何一个:
getCPos () {
local v=() t=$(stty -g)
stty -echo
printf "3[6n"
IFS='[;' read -ra v -d R
stty $t
CPos=(${v[@]:1})
}
will work exactly same, while under VT220compatible TERM.
将完全相同,而在VT220兼容 TERM 下。
More info
更多信息
You may found some doc there:
您可能会在那里找到一些文档:
VT220 Programmer Reference Manual - Chapter 4
4.17.2 Device Status Report (DSR)
...
Host to VT220 (Req 4 cur pos) CSI 6 n "Please report your cursor position using a CPR (not DSR) control sequence." VT220 to host (CPR response) CSI Pv; Ph R "My cursor is positioned at _____ (Pv); _____ (Ph)." Pv = vertical position (row) Ph = horizontal position (column)
4.17.2 设备状态报告(DSR)
...
Host to VT220 (Req 4 cur pos) CSI 6 n "Please report your cursor position using a CPR (not DSR) control sequence." VT220 to host (CPR response) CSI Pv; Ph R "My cursor is positioned at _____ (Pv); _____ (Ph)." Pv = vertical position (row) Ph = horizontal position (column)
回答by mr_jrt
In the interests of portability I've had a go at making a vanilla POSIX-compatible version that will run in shells like dash:
为了可移植性,我尝试制作一个与 POSIX 兼容的 vanilla 版本,该版本将在像 dash 这样的 shell 中运行:
#!/bin/sh
exec < /dev/tty
oldstty=$(stty -g)
stty raw -echo min 0
tput u7 > /dev/tty
sleep 1
IFS=';' read -r row col
stty $oldstty
row=$(expr $(expr substr $row 3 99) - 1) # Strip leading escape off
col=$(expr ${col%R} - 1) # Strip trailing 'R' off
echo $col,$row
...but I can't seem to find a viable alternative for bash's 'read -d'. Without the sleep, the script misses the return output entirely...
...但我似乎找不到 bash 的“ read -d”的可行替代方案。如果没有睡眠,脚本将完全错过返回输出......
回答by Alissa H
In case anyone else is looking for this, I came across another solution here: https://github.com/dylanaraps/pure-bash-bible#get-the-current-cursor-position
如果其他人正在寻找这个,我在这里遇到了另一个解决方案:https: //github.com/dylanaraps/pure-bash-bible#get-the-current-cursor-position
Below is a slightly modified version with comments.
下面是一个带有注释的稍微修改的版本。
#!/usr/bin/env bash
#
# curpos -- demonstrate a method for fetching the cursor position in bash
# modified version of https://github.com/dylanaraps/pure-bash-bible#get-the-current-cursor-position
#
#========================================================================================
#-
#- THE METHOD
#-
#- IFS='[;' read -p $'\e[6n' -d R -a pos -rs || echo "failed with error: $? ; ${pos[*]}"
#-
#- THE BREAKDOWN
#-
#- $'\e[6n' # escape code, {ESC}[6n;
#-
#- This is the escape code that queries the cursor postion. see XTerm Control Sequences (1)
#-
#- same as:
#- $ echo -en '3[6n'
#- $ 6;1R # '^[[6;1R' with nonprintable characters
#-
#- read -p $'\e[6n' # read [-p prompt]
#-
#- Passes the escape code via the prompt flag on the read command.
#-
#- IFS='[;' # characters used as word delimiter by read
#-
#- '^[[6;1R' is split into array ( '^[' '6' '1' )
#- Note: the first element is a nonprintable character
#-
#- -d R # [-d delim]
#-
#- Tell read to stop at the R character instead of the default newline.
#- See also help read.
#-
#- -a pos # [-a array]
#-
#- Store the results in an array named pos.
#- Alternately you can specify variable names with positions: <NONPRINTALBE> <ROW> <COL> <NONPRINTALBE>
#- Or leave it blank to have all results stored in the string REPLY
#-
#- -rs # raw, silent
#-
#- -r raw input, disable backslash escape
#- -s silent mode
#-
#- || echo "failed with error: $? ; ${pos[*]}"
#-
#- error handling
#-
#- ---
#- (1) XTerm Control Sequences
#- http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Functions-using-CSI-_-ordered-by-the-final-character_s_
#========================================================================================
#-
#- CAVEATS
#-
#- - if this is run inside of a loop also using read, it may cause trouble.
#- to avoid this, use read -u 9 in your while loop. See safe-find.sh (*)
#-
#-
#- ---
#- (2) safe-find.sh by l0b0
#- https://github.com/l0b0/tilde/blob/master/examples/safe-find.sh
#=========================================================================================
#================================================================
# fetch_cursor_position: returns the users cursor position
# at the time the function was called
# output "<row>:<col>"
#================================================================
fetch_cursor_position() {
local pos
IFS='[;' read -p $'\e[6n' -d R -a pos -rs || echo "failed with error: $? ; ${pos[*]}"
echo "${pos[1]}:${pos[2]}"
}
#----------------------------------------------------------------------
# print ten lines of random widths then fetch the cursor position
#----------------------------------------------------------------------
#
MAX=$(( $(tput cols) - 15 ))
for i in {1..10}; do
cols=$(( $RANDOM % $MAX ))
printf "%${cols}s" | tr " " "="
echo " $(fetch_cursor_position)"
done
回答by geohump
The tput commands are what you need to use. simple, fast, no output to the screen.
您需要使用 tput 命令。简单,快速,没有输出到屏幕。
#!/bin/bash
col=`tput col`;
line=`tput line`;