Ottieni la posizione del cursore verticale


10

Potrebbe sembrare abbastanza strano, ma so come impostare la posizione del cursore verticale in Bash in questo modo:

echo -e "\e[12H"

Questo sposta il cursore sulla dodicesima riga (a partire da 1).

Quindi, come posso ottenere la posizione del cursore (numero di riga) usando Linux Bash? Sarebbe utile se potessi semplicemente memorizzare questo valore in una variabile in modo da poter calcolare con esso.

MODIFICARE:

Questo è l'errore che ottengo:

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

Vedi anche uno script di esempio (non il più semplice perché quello aveva vincoli aggiuntivi).
Gilles 'SO- smetti di essere malvagio' il

Risposte:


5

Sono stato in grado di utilizzare alcuni degli esempi tratti dallo stesso articolo su SO, intitolato: Come ottenere la posizione del cursore in bash? . Sto pubblicando questo qui solo per dimostrare che funzionano e che il contenuto delle soluzioni è in realtà anche in U&L.

Soluzioni Bash

Dall'interno di una sceneggiatura

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

NOTA: ho modificato leggermente l'output!

Esempio

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

Shell interattiva

Questa catena di comandi ha funzionato per ottenere le posizioni di riga e colonna del cursore:

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

Esempio

$ 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

NOTA: questo metodo non sembra essere utilizzabile da alcun tipo di script. Anche i semplici comandi in un terminale interattivo non hanno funzionato per me. Per esempio:

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

si blocca indefinitamente.

soluzioni dash / sh

Dall'interno di una sceneggiatura

Questa soluzione è per i sistemi Ubuntu / Debian di serie dash, conforme a POSIX. Per questo motivo, il readcomando non supporta l' -dopzione tra le altre differenze.

Per ovviare a questo c'è questa soluzione che utilizza un sleep 1al posto -ddell'interruttore. Questo non è l'ideale ma offre almeno una soluzione funzionante.

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

Esempio

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

Shell interattiva

Non riuscivo a trovare una soluzione praticabile che funzionasse solo shin una shell interattiva.


Questo sembra funzionare solo con bash. E non con sh. Personalmente preferisco sh. Quindi, come potrei usarlo con sh?
BrainStone,

1
@BrainStone - fammi fare ricerche e vedere se non riesco a trovare un modo.
slm

sh rowcol.sh. Non importa cosa hai messo nella prima riga ( #!/bin/basho #!/bin/sh) o che fine ha il file!
BrainStone,

@BrainStone - ma penso shsia solo una modalità di compatibilità di bash. Quando lo faccio ( sh rowcol.bash) funziona, allora non funziona per te?
slm

1
@BrainStone - si potrebbe fare un alias, alias sh=bash?
slm

17

Utilizzando l' -popzione invece di echoho trovato risolto il problema di sospensione in uno script. Testato con GNU bash, version 3.00.16(1)-release (x86_64-redhat-linux-gnu).

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

funziona in modo interattivo o in uno script:

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

Uscite:

$. / Cursor.sh
3.00.16 (1) -RELEASE
6; 11 6 11
26; 16 26 16

Funziona molto bene Purtroppo, tuttavia, non funziona nei processi in background e mentre scorre lo schermo, la linea sotto la colonna salvata cambia.
leondepeon,

4

È possibile ottenere la posizione del cursore tramite ANSI CSI DSR(Device Status Report): \e[6n. Nota che lo restituisce in un formato simile a ANSI CSR CUP(Posizione cursore) menzionato nella domanda, tuttavia segue il modulo \e[n;mR(dove n è la riga e m la colonna).

Maggiori dettagli sui codici di escape ANSI su wikipedia .

Per ottenere il valore in una variabile, è stato risposto su StackOverflow .

Come menzionato in una precedente risposta / commento (e dettagliato nell'articolo di Wikipedia), questi codici non sono sempre portatili (dal terminale al terminale e dal sistema operativo al sistema operativo). Penso ancora che questo sia meglio gestito con termcap / curses;)


E come potrei memorizzarlo in una variabile?
BrainStone,

Non riesco a farlo funzionare. Ho sempre problemi con echo -e, echo -ene read .... Questo succede solo quando il codice è presente nel file! Non lo capisco davvero!
BrainStone,

Sembra che abbia rotto un po 'di impostazione. echo -eha funzionato prima ma ora no! Cosa potrebbe aver causato questo e come posso ripristinarlo?
BrainStone,

2

Con la shsintassi 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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.