Dapatkan posisi kursor vertikal

10

Ini mungkin terdengar aneh, tapi saya tahu cara mengatur posisi kursor vertikal di Bash seperti ini:

echo -e "\e[12H"

Ini memindahkan kursor ke garis ke-12 (dimulai dengan 1).

Jadi bagaimana cara mendapatkan posisi kursor (nomor baris) menggunakan linux bash? Akan sangat membantu jika saya bisa menyimpan nilai ini dalam suatu variabel sehingga saya dapat menghitungnya.

EDIT:

Ini adalah kesalahan yang saya dapatkan:

$ sh rowcol.sh
-en
    read: 9: Illegal option -d
                              test.sh: 12: Bad substitution
BrainStone
sumber
Lihat juga contoh skrip (bukan yang paling sederhana karena yang memiliki kendala tambahan).
Gilles 'SANGAT berhenti menjadi jahat'

Jawaban:

5

Saya dapat menggunakan beberapa contoh dari artikel yang sama di SO, berjudul: Bagaimana cara mendapatkan posisi kursor di bash? . Saya memposting ini di sini hanya untuk menunjukkan bahwa mereka berfungsi dan bahwa isi solusi sebenarnya ada di U&L juga.

Solusi bash

Dari dalam naskah

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

CATATAN: Saya sedikit mengubah output!

Contoh

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

Shell interaktif

Rantai perintah ini berfungsi untuk mendapatkan posisi baris dan kolom dari kursor:

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

Contoh

$ 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

CATATAN: Metode ini tampaknya tidak dapat digunakan dari semua jenis skrip. Bahkan perintah sederhana di terminal interaktif tidak bekerja untuk saya. Sebagai contoh:

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

hanya hang tanpa batas.

solusi dash / sh

Dari dalam naskah

Solusi ini untuk sistem Ubuntu / Debian yang disertakan dash, yang sesuai dengan POSIX. Karena itu, readperintah tidak mendukung -dperalihan di antara perbedaan lainnya.

Untuk menyiasati ini ada solusi ini yang menggunakan sleep 1di tempat -dsaklar. Ini tidak ideal tetapi menawarkan setidaknya solusi yang berfungsi.

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

Contoh

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

Shell interaktif

Saya tidak dapat menemukan solusi yang bisa diterapkan yang berfungsi hanya shdalam shell interaktif.

slm
sumber
Ini sepertinya hanya bekerja dengan bash. Dan tidak dengan sh. Saya pribadi lebih suka sh. Jadi bagaimana saya bisa menggunakan ini dengan sh?
BrainStone
1
@BrainStone - biarkan saya meneliti dan melihat apakah saya tidak dapat menemukan jalan.
slm
sh rowcol.sh. Tidak masalah apa yang Anda masukkan di baris pertama ( #!/bin/bashatau #!/bin/sh) atau apa yang mengakhiri file!
BrainStone
@ TrainStone - tapi saya pikir shhanya mode kompatibilitas bash. Ketika saya melakukan itu ( sh rowcol.bash) itu berhasil, apakah itu tidak berhasil untuk Anda?
slm
1
@BrainStone - Anda bisa membuat alias , alias sh=bash?
slm
17

Menggunakan -popsi bukannya echosaya menemukan memecahkan masalah yang menggantung dalam skrip. Diuji dengan GNU bash, version 3.00.16(1)-release (x86_64-redhat-linux-gnu).

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

bekerja secara interaktif atau dalam sebuah skrip:

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

Output:

$. / cursor.sh
3.00.16 (1) - dirilis
6; 11 6 11
26; 16 26 16
pengguna102015
sumber
Ini bekerja dengan sangat baik. Sayangnya, itu tidak berfungsi dalam proses latar belakang, dan saat layar bergulir, garis di bawah kolom yang disimpan berubah.
leondepeon
4

Anda bisa mendapatkan posisi kursor melalui ANSI CSI DSR(Perangkat Status Report): \e[6n. Catatan itu mengembalikannya dalam format yang mirip dengan ANSI CSR CUP(Posisi Kursor) yang Anda sebutkan dalam pertanyaan Anda, namun itu mengikuti bentuk \e[n;mR(di mana n adalah baris dan m kolom).

Lebih detail kode pelarian ANSI di wikipedia .

Untuk mendapatkan nilai ke dalam variabel, ini dijawab pada StackOverflow .

Seperti disebutkan dalam jawaban / komentar sebelumnya (dan dirinci dalam artikel wikipedia), kode-kode ini tidak selalu portabel (dari terminal ke terminal dan OS ke OS). Saya masih berpikir ini lebih baik ditangani dengan termcap / kutukan;)

Drav Sloan
sumber
Dan bagaimana saya bisa menyimpan ini dalam sebuah variabel?
BrainStone
Saya tidak bisa membuatnya bekerja. Saya selalu mendapat masalah echo -e, echo -endan read .... Ini hanya terjadi ketika kode hadir dalam file! Saya tidak begitu mengerti ini!
BrainStone
Sepertinya saya melanggar beberapa pengaturan. echo -ebekerja sebelumnya tetapi sekarang tidak! Apa yang mungkin menyebabkan ini dan bagaimana cara mengembalikannya?
BrainStone
2

Dengan shsintaks 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
Stéphane Chazelas
sumber