In uno script bash, voglio ottenere la colonna del cursore in una variabile. Sembra usare il codice di escape ANSI {ESC}[6n
è l’unico modo per ottenerlo, ad esempio il seguente modo:
# 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
Sfortunatamente, questo stampa i caratteri sullo standard output e voglio farlo in silenzio. Inoltre, questo non è molto portatile …
C’è un modo puro per ottenere questo?
Devi ricorrere a trucchi sporchi:
#!/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))
So che potrebbe essere risolto da sapere, ma si potrebbe semplicemente dire leggere per lavorare in silenzio con “-s”:
echo -en "\E[6n" read -sdR CURPOS CURPOS=${CURPOS#*[}
E poi CURPOS è uguale a qualcosa come “21; 3”.
Nell’interesse della portabilità ho provato a realizzare una versione compatibile con POSIX vanilla che funzionerà in shell come 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
… ma non riesco a trovare un’alternativa valida per bash’s ‘ read -d ‘. Senza il sonno, lo script manca completamente l’output di ritorno …
Come funzione, imposta una variabile specifica, usando i comandi definiti dall’utente di ncurses:
getCPos () { local v=() t=$(stty -g) stty -echo tput u7 IFS='[;' read -rd R -av stty $t CPos=(${v[@]:1}) }
Di adesso:
getCPos echo $CPos 21 echo ${CPos[1]} 1 echo ${CPos[@]} 21 1 declare -p CPos declare -a CPos=([0]="48" [1]="1")
Nota: utilizzo il comando ncurses
: tput u7
alla riga #4
nella speranza che questo rimanga più portatile rispetto all’utilizzo della stringa VT220
tramite comando: printf "\033[6n"
… Non sono sicuro: comunque funzionerà con nessuno di essi:
getCPos () { local v=() t=$(stty -g) stty -echo printf "\033[6n" IFS='[;' read -ra v -d R stty $t CPos=(${v[@]:1}) }
funzionerà esattamente allo stesso modo, mentre sotto VT220 compatibile TERM.
Puoi trovare alcuni documenti lì:
Manuale di riferimento del programmatore VT220 – Capitolo 4
4.17.2 Rapporto sullo stato del dispositivo (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)
I comandi tput sono ciò che è necessario utilizzare. semplice, veloce, nessuna uscita sullo schermo.
#!/bin/bash col=`tput col`; line=`tput line`;