Получить вертикальную позицию курсора

10

Это может звучать довольно странно, но я знаю, как установить положение вертикального курсора в Bash следующим образом:

echo -e "\e[12H"

Это перемещает курсор на 12-ю строку (начиная с 1).

Итак, как мне получить позицию курсора (номер строки), используя Linux Bash? Было бы полезно, если бы я мог просто сохранить это значение в переменной, чтобы я мог рассчитывать с ним.

РЕДАКТИРОВАТЬ:

Это ошибка, которую я получаю:

$ sh rowcol.sh
-en
    read: 9: Illegal option -d
                              test.sh: 12: Bad substitution
BrainStone
источник
Смотрите также пример скрипта (не самый простой, потому что у него были дополнительные ограничения).
Жиль "ТАК ... перестать быть злым"

Ответы:

5

Я смог использовать некоторые примеры из той же статьи о SO под названием: Как получить позицию курсора в bash? , Я публикую это здесь только для того, чтобы показать, что они работают и что содержание решений на самом деле также находится в U & L.

Решения Bash

Изнутри скрипта

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

echo "(row,col): $row,$col"

ПРИМЕЧАНИЕ: я немного изменил вывод!

пример

$ ./rowcol.bash 
(row,col): 43,0
$ clear
$ ./rowcol.bash 
(row,col): 1,0

Интерактивная оболочка

Эта цепочка команд работала для получения позиций строки и столбца курсора:

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

пример

$ echo -en "\E[6n";read -sdR CURPOS; CURPOS=${CURPOS#*[};echo "${CURPOS}"
13;1
$ clear
$ echo -en "\E[6n";read -sdR CURPOS; CURPOS=${CURPOS#*[};echo "${CURPOS}"
2;1

ПРИМЕЧАНИЕ. Этот метод не подходит для любого типа сценария. Даже простые команды в интерактивном терминале у меня не работали. Например:

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

просто висит бесконечно.

решения тире / ш

Изнутри скрипта

Это решение предназначено для систем Ubuntu / Debian, которые поставляются со dashстандартным POSIX. Из-за этого readкоманда не поддерживает -dпереключение среди других различий.

Чтобы обойти это, есть решение, которое использует sleep 1вместо -dпереключателя. Это не идеально, но предлагает хотя бы рабочее решение.

#!/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 "(row,col): $col,$row"

пример

$ ./rowcol.sh 
(row,col): 0,24
$ clear
$ ./rowcol.sh 
(row,col): 0,1

Интерактивная оболочка

Я не мог найти работоспособное решение, которое работало бы просто shв интерактивной оболочке.

SLM
источник
Кажется, это работает только с Bash. И не с ш. Я лично предпочитаю ш. Так как я могу использовать это с sh?
BrainStone
1
@BrainStone - позвольте мне исследовать и посмотреть, не могу ли я найти способ.
СЛМ
sh rowcol.sh, Неважно, что вы помещаете в первую строку ( #!/bin/bashили #!/bin/sh) или в конце файла!
BrainStone
@BrainStone - но я думаю, что shэто просто режим совместимости bash. Когда я делаю это ( sh rowcol.bash), это работает, разве это не работает для вас тогда?
СЛМ
1
@BrainStone - вы могли бы сделать псевдоним, alias sh=bash?
СЛМ
17

Использование -pопции вместо echoнайденной решило проблему зависания в скрипте. Проверено с GNU bash, version 3.00.16(1)-release (x86_64-redhat-linux-gnu).

IFS=';' read -sdR -p $'\E[6n' ROW COL;echo "${ROW#*[}"

работает в интерактивном режиме или в сценарии:

#!/usr/bin/env bash
function pos
{
    local CURPOS
    read -sdR -p $'\E[6n' CURPOS
    CURPOS=${CURPOS#*[} # Strip decoration characters <ESC>[
    echo "${CURPOS}"    # Return position in "row;col" format
}
function row
{
    local COL
    local ROW
    IFS=';' read -sdR -p $'\E[6n' ROW COL
    echo "${ROW#*[}"
}
function col
{
    local COL
    local ROW
    IFS=';' read -sdR -p $'\E[6n' ROW COL
    echo "${COL}"
}
tput sc         # Save cursor position
tput cup 5 10   # Move to row 6 col 11
POS1=$(pos)     # Get the cursor position
ROW1=$(row)
COL1=$(col)
tput cup 25 15  # Move to row 25 col 15
POS2=$(pos)     # Get the cursor position
ROW2=$(row)
COL2=$(col)
tput rc # Restore cursor position
echo $BASH_VERSION
echo $POS1 $ROW1 $COL1
echo $POS2 $ROW2 $COL2

Выходы:

$. / Cursor.sh
3.00.16 (1) -release
6; 11 6 11
26; 16 26 16
user102015
источник
Это работает очень хорошо. К сожалению, это не работает в фоновых процессах, и по мере прокрутки экрана строка под сохраненным столбцом изменяется.
leondepeon
4

Вы можете получить позицию курсора с помощью ANSI CSI DSR(Device Status Report): \e[6n. Обратите внимание, что он возвращает его в формате, аналогичном ANSI CSR CUP(позиция курсора), который вы упоминаете в своем вопросе, однако он следует форме \e[n;mR(где n - строка, а m - столбец).

Подробнее о кодах выхода ANSI в Википедии .

Для получения значения в переменную ответили на StackOverflow .

Как упоминалось в предыдущем ответе / комментарии (и подробно описано в статье в Википедии), эти коды не всегда переносимы (от терминала к терминалу и от ОС к ОС). Я все еще думаю, что это лучше обрабатывается с помощью termcap / curses;)

Драв Слоан
источник
И как я могу сохранить это в переменной?
BrainStone
Я не могу заставить это работать. У меня всегда проблемы с echo -e, echo -enа read .... Это происходит только тогда, когда код присутствует в файле! Я не очень понимаю это!
BrainStone
Кажется, я нарушил некоторые настройки. echo -eраньше работал, а сейчас нет! Что могло вызвать это и как я могу восстановить это?
BrainStone
2

С shсинтаксисом POSIX :

if [ -t 0 ] && [ -t 1 ]; then
  old_settings=$(stty -g) || exit
  stty -icanon -echo min 0 time 3 || exit
  printf '\033[6n'
  pos=$(dd count=1 2> /dev/null)
  pos=${pos%R*}
  pos=${pos##*\[}
  x=${pos##*;} y=${pos%%;*}
  stty "$old_settings"
fi
Стефан Шазелас
источник