Отримайте вертикальне положення курсору


10

Це може здатися досить дивним, але я знаю, як встановити вертикальну позицію курсора в Bash так:

echo -e "\e[12H"

Це переміщує курсор до 12-го рядка (починаючи з 1).

Тож як я можу отримати позицію курсора (номер рядка) за допомогою linux bash? Було б корисно, якби я міг просто зберегти це значення у змінній, щоб я міг обчислити його.

Редагувати:

Це помилка, яку я отримую:

$ sh rowcol.sh
-en
    read: 9: Illegal option -d
                              test.sh: 12: Bad substitution

Дивіться також приклад сценарію (не найпростіший, тому що той мав додаткові обмеження).
Жил "ТАК - перестань бути злим"

Відповіді:


5

Мені вдалося використати деякі приклади з тієї ж статті про SO під назвою: Як отримати положення курсору в bash? . Я розміщую це тут лише для того, щоб показати, що вони працюють і що вміст рішень насправді є і на U&L.

Рішення Баша

Зсередини сценарій

#!/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в інтерактивній оболонці.


Здається, це працює лише з bash. І не зі ш. Я особисто віддаю перевагу ш. То як я можу це використати з ш?
BrainStone

1
@BrainStone - дозвольте мені дослідити і побачити, чи не можу я знайти спосіб.
slm

sh rowcol.sh. Не має значення, що ви ставите в перший рядок ( #!/bin/bashабо #!/bin/sh), або що закінчується у файлі!
BrainStone

@BrainStone - але я думаю, що shце лише режим сумісності bash. Коли я це роблю ( sh rowcol.bash), це працює, чи це не працює для тебе тоді?
slm

1
@BrainStone - ти можеш зробити псевдонім , alias sh=bash?
slm

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) -випуск
6; 11 6 11
26; 16 26 16

Це працює дуже добре. Однак, на жаль, він не працює у фонових процесах, і коли екран прокручується, рядок під збереженим стовпцем змінюється.
leondepeon

4

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

Більш детальна інформація про коди втечі ANSI на wikipedia .

Щоб отримати значення у змінній, на це відповіли в StackOverflow .

Як було сказано в попередній відповіді / коментарі (та детально описано у статті вікіпедії), ці коди не завжди є портативними (від терміналу до терміналу та ОС до ОС). Я все ще думаю, що це краще вирішувати термінами / прокльонами;)


І як я міг зберігати це у змінній?
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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.