Shell Terminal – How to Get Vertical Cursor Position

shellterminal

This might sound pretty weird, but I know how to set the vertical cursor position in Bash like this:

echo -e "\e[12H"

This moves the cursor to the 12th line (starting with 1).

So how do I get the cursor position (line number) using linux bash? It would be helpful if I could simply store this value in a variable so I can calculate with it.

EDIT:

This is the error I get:

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

Best Answer

I was able to use some of the examples from the same article on SO, titled: How to get the cursor position in bash?. I'm posting this here just to show that they work and that the contents of solutions is actually on U&L as well.

Bash solutions

From inside a script

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

NOTE: I changed the output slightly!

Example

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

Interactive shell

This command chain worked for getting the row and column positions of the cursor:

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

Example

$ 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

NOTE: This method doesn't appear to be usable from any type of script. Even simple commands in an interactive terminal didn't work for me. For example:

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

just hangs indefinitely.

dash/sh solutions

From inside a script

This solution is for Ubuntu/Debian systems that come stock with dash, which is POSIX compliant. Because of this, the read command doesn't support the -d switch among other differences.

To get around this there is this solution which uses a sleep 1 in place of the -d switch. This isn't ideal but offers at least a working solution.

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

Example

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

Interactive shell

I couldn't find a workable solution that worked for just sh in an interactive shell.