2010-04-04 1 views
20

In uno script bash, voglio ottenere la colonna del cursore in una variabile. Sembra che utilizzando il codice di escape ANSI {ESC}[6n è l'unico modo per farlo, ad esempio, nel seguente modo:Come ottenere la posizione del cursore in bash?

# 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 

Purtroppo, questo stampa caratteri sullo standard output e voglio farlo in silenzio. Inoltre, questo non è molto portatile ...

Esiste un modo semplice per raggiungere questo obiettivo?

risposta

29

Bisogna ricorrere a sporchi trucchi:

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

Wow, non ho pensato di cambiare terminale, grazie! – nicoulaj

+0

come possiamo usare questo codice 'bash' nella lingua' C'? – Rasoul

+1

@Rasoul: dovresti chiedere una domanda a parte. –

8

So che può essere risolto con un know, ma si potrebbe semplicemente dire leggere a lavorare in silenzio con la "s":

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

E poi CURPOS è uguale a qualcosa come "21; 3".

+1

Per me questo funziona nella shell interattiva ma non all'interno di uno script – etuardu

+0

Grazie per questo, ho dovuto riempire il resto della linea in un Makefile e ho finito con questo all'interno di una funzione: "echo" \ 033 [6n \ c " ; leggi -sdR CURPOS; COLS_LEFT = "$$ (expr $$ TERM_COLS - $$ (echo $$ {CURPOS} | cut -d ';' -f 2;) + 1)"; ' – mVChr

+0

' echo -en "\ 033 [6n"; dormire 1; read -sdR' Questo metodo non è corretto. È necessario disabilitare lflag ECHO prima del comando echo. – zhangyoufu

2

Nell'interesse della portabilità che ho avuto un andare a fare una versione POSIX compatibile con vaniglia che verrà eseguito in conchiglie come cruscotto:

#!/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 'di bash leggi -d'. Senza il sonno, lo script manca completamente l'output di ritorno ...

-6

I comandi tput sono ciò che è necessario utilizzare. semplice, veloce, nessuna uscita sullo schermo.

#!/bin/bash 
col=`tput col`; 
line=`tput line`; 
+10

Quale sistema operativo e versione stai usando che questo funziona per te? Sul mio sistema, non ci sono funzionalità terminfo chiamate "col" e "line". Tuttavia, esistono i plurali "cols" e "linee", ma restituiscono il numero totale di colonne e linee anziché la posizione corrente del cursore. –