Vertikale Cursorposition abrufen

10

Das mag ziemlich seltsam klingen, aber ich weiß, wie man die vertikale Cursorposition in Bash wie folgt einstellt:

echo -e "\e[12H"

Dies bewegt den Cursor in die 12. Zeile (beginnend mit 1).

Wie erhalte ich die Cursorposition (Zeilennummer) mit Linux Bash? Es wäre hilfreich, wenn ich diesen Wert einfach in einer Variablen speichern könnte, damit ich damit rechnen kann.

BEARBEITEN:

Dies ist der Fehler, den ich bekomme:

$ sh rowcol.sh
-en
    read: 9: Illegal option -d
                              test.sh: 12: Bad substitution
BrainStone
quelle
Siehe auch ein Beispielskript (nicht das einfachste, da dieses zusätzliche Einschränkungen hatte).
Gilles 'SO - hör auf böse zu sein'

Antworten:

5

Ich konnte einige Beispiele aus demselben Artikel über SO mit dem Titel verwenden: Wie erhalte ich die Cursorposition in Bash? . Ich poste dies hier nur, um zu zeigen, dass sie funktionieren und dass der Inhalt von Lösungen tatsächlich auch auf U & L ist.

Bash-Lösungen

Aus einem Skript heraus

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

HINWEIS: Ich habe die Ausgabe leicht verändert!

Beispiel

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

Interaktive Shell

Diese Befehlskette diente zum Abrufen der Zeilen- und Spaltenpositionen des Cursors:

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

Beispiel

$ 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

HINWEIS: Diese Methode scheint von keinem Skripttyp aus verwendbar zu sein. Selbst einfache Befehle in einem interaktiven Terminal haben bei mir nicht funktioniert. Beispielsweise:

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

hängt nur auf unbestimmte Zeit.

Dash / Sh-Lösungen

Aus einem Skript heraus

Diese Lösung ist für Ubuntu / Debian-Systeme vorgesehen, die auf Lager dashsind und POSIX-kompatibel sind. Aus diesem Grund unterstützt der readBefehl den -dSchalter unter anderem nicht.

Um dies zu umgehen, gibt es diese Lösung, sleep 1bei der anstelle des -dSchalters ein verwendet wird. Dies ist nicht ideal, bietet aber zumindest eine funktionierende Lösung.

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

Beispiel

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

Interaktive Shell

Ich konnte keine praktikable Lösung finden, die nur shin einer interaktiven Shell funktioniert .

slm
quelle
Dies scheint nur mit Bash zu funktionieren. Und nicht mit sh. Ich persönlich bevorzuge sh. Wie könnte ich das mit sh verwenden?
BrainStone
1
@BrainStone - lass mich recherchieren und sehen, ob ich keinen Weg finde.
slm
sh rowcol.sh. Es spielt keine Rolle, was Sie in die erste Zeile ( #!/bin/bashoder #!/bin/sh) setzen oder welches Ende die Datei hat!
BrainStone
@BrainStone - aber ich denke shist nur ein Kompatibilitätsmodus von bash. Wenn ich das mache ( sh rowcol.bash) funktioniert es, funktioniert es dann nicht für dich?
slm
1
@BrainStone - Sie könnten einen Alias ​​erstellen , alias sh=bash?
slm
17

Die Verwendung der -pOption anstelle von echoIch fand das Problem mit dem Hängen in einem Skript gelöst. Getestet mit GNU bash, version 3.00.16(1)-release (x86_64-redhat-linux-gnu).

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

arbeitet interaktiv oder in einem Skript:

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

Ausgänge:

$. / cursor.sh
3.00.16 (1) -Freisetzung
6; 11 6 11
26; 16 26 16
user102015
quelle
Das funktioniert sehr gut. Leider funktioniert es nicht in Hintergrundprozessen, und während der Bildschirm rollt, ändert sich die Zeile unter der gespeicherten Spalte.
leondepeon
4

Sie können die Cursorposition über ANSI CSI DSR(Gerätestatusbericht) abrufen : \e[6n. Beachten Sie, dass es in einem ähnlichen Format wie ANSI CSR CUP(Cursorposition) zurückgegeben wird, das Sie in Ihrer Frage erwähnt haben, jedoch dem Formular folgt \e[n;mR(wobei n die Zeile und m die Spalte ist).

Weitere Details zu ANSI-Escape-Codes finden Sie auf Wikipedia .

Um den Wert in eine Variable zu bekommen, wurde dies auf StackOverflow beantwortet .

Wie in einer vorherigen Antwort / einem Kommentar erwähnt (und im Wikipedia-Artikel ausführlich beschrieben), sind diese Codes nicht immer portabel (von Terminal zu Terminal und von Betriebssystem zu Betriebssystem). Ich denke immer noch, dass dies mit Termcap / Flüchen besser gehandhabt wird;)

Drav Sloan
quelle
Und wie könnte ich das in einer Variablen speichern?
BrainStone
Ich kann es nicht zum Laufen bringen. Ich bekomme immer wieder Probleme mit echo -e, echo -enund read .... Dies geschieht nur, wenn der Code in der Datei vorhanden ist! Ich verstehe das nicht wirklich!
BrainStone
Es scheint, als hätte ich eine Einstellung gebrochen. echo -ehat vorher funktioniert, aber jetzt nicht! Was könnte dies verursacht haben und wie kann ich es wiederherstellen?
BrainStone
2

Mit POSIX- shSyntax:

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
quelle