Как получить позицию курсора в bash? - PullRequest
23 голосов
/ 04 апреля 2010

В bash-скрипте я хочу получить курсорный столбец в переменной.Похоже, что использование escape-кода ANSI {ESC}[6n - единственный способ получить его, например, следующим образом:

# Query the cursor position
echo -en '\033[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

К сожалению, это выводит символы на стандартный вывод, и я хочу сделать это молча,Кроме того, это не очень переносимо ...

Есть ли способ достижения цели в чистом виде?

Ответы [ 6 ]

32 голосов
/ 04 апреля 2010

Вы должны прибегнуть к грязным уловкам:

#!/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 "\033[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))
9 голосов
/ 14 мая 2011

Вы можете сказать read, чтобы он работал тихо с флагом -s:

echo -en "\E[6n"
read -sdR CURPOS
CURPOS=${CURPOS#*[}

И тогда CURPOS равен чему-то вроде 21;3.

3 голосов
/ 20 августа 2018

Моя (две) версии того же ...

Как функция, устанавливающая определенную переменную, используя определяемые пользователем команды ncurses :

getCPos () { 
    local v=() t=$(stty -g)
    stty -echo
    tput u7
    IFS='[;' read -rd R -a v
    stty $t
    CPos=(${v[@]:1})
}

Чем сейчас:

getCPos 
echo $CPos
21
echo ${CPos[1]}
1
echo ${CPos[@]}
21 1

declare -p CPos
declare -a CPos=([0]="48" [1]="1")

Примечание: Я использую ncurses команду: tput u7 в строке #4 в надежде, что это останется на переносным , чем при использовании VT220 строка по команде: printf "\033[6n" ... Не уверен: в любом случае это будет работать с любым из них:

getCPos () { 
    local v=() t=$(stty -g)
    stty -echo
    printf "\033[6n"
    IFS='[;' read -ra v -d R
    stty $t
    CPos=(${v[@]:1})
}

будет работать точно так же, в то время как VT220 совместимый TERM.

Подробнее

Вы можете найти там несколько документов:

Справочное руководство по программированию VT220 - Глава 4

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)
2 голосов
/ 09 сентября 2012

В интересах переносимости я попытался создать ванильную POSIX-совместимую версию, которая будет работать в оболочках вроде dash:

#!/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

... но я не могу найти жизнеспособную альтернативу для bash ' read -d '. Без сна скрипт полностью пропускает возвращаемый результат ...

1 голос
/ 23 октября 2018

В случае, если кто-то еще ищет это, я столкнулся с другим решением здесь: https://github.com/dylanaraps/pure-bash-bible#get-the-current-cursor-position

Ниже приведена слегка измененная версия с комментариями.

#!/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 '\033[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
0 голосов
/ 11 ноября 2012

Команды tput - это то, что вам нужно использовать. просто, быстро, без вывода на экран.

#!/bin/bash
col=`tput col`;
line=`tput line`;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...