รับตำแหน่งเคอร์เซอร์แนวตั้ง


10

นี่อาจฟังดูแปลก ๆ แต่ฉันรู้วิธีตั้งตำแหน่งเคอร์เซอร์แนวตั้งใน Bash ดังนี้:

echo -e "\e[12H"

สิ่งนี้เลื่อนเคอร์เซอร์ไปที่บรรทัดที่ 12 (เริ่มต้นด้วย 1)

ดังนั้นฉันจะรับตำแหน่งเคอร์เซอร์ (หมายเลขบรรทัด) โดยใช้ linux bash ได้อย่างไร มันจะมีประโยชน์ถ้าฉันสามารถเก็บค่านี้ไว้ในตัวแปรเพื่อให้ฉันสามารถคำนวณได้

แก้ไข:

นี่เป็นข้อผิดพลาดที่ฉันได้รับ:

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

ดูสคริปต์ตัวอย่าง (ไม่ใช่สคริปต์ที่ง่ายที่สุดเนื่องจากมีข้อ จำกัด เพิ่มเติม)
Gilles 'หยุดความชั่วร้าย' ใน

คำตอบ:


5

ฉันสามารถใช้ตัวอย่างจากบทความเดียวกันใน SO ชื่อเรื่อง: วิธีการรับตำแหน่งเคอร์เซอร์ในทุบตี? . ฉันโพสต์ที่นี่เพียงเพื่อแสดงให้เห็นว่าพวกเขาทำงานและเนื้อหาของการแก้ปัญหาเป็นจริงใน U&L เช่นกัน

Bash solutions

จากภายในสคริปต์

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

หมายเหตุ:ฉันเปลี่ยนผลลัพธ์เล็กน้อย!

ตัวอย่าง

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

เชลล์แบบโต้ตอบ

กลุ่มคำสั่งนี้ทำงานเพื่อรับตำแหน่งแถวและคอลัมน์ของเคอร์เซอร์:

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

ตัวอย่าง

$ 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

หมายเหตุ:วิธีการนี้ดูเหมือนจะไม่สามารถใช้งานได้กับสคริปต์ประเภทใด ๆ แม้แต่คำสั่งง่ายๆในเทอร์มินัลเชิงโต้ตอบก็ไม่ได้ผลสำหรับฉัน ตัวอย่างเช่น:

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

เพียงแฮงค์ไปเรื่อย ๆ

โซลูชันเส้นประ / sh

จากภายในสคริปต์

โซลูชันนี้สำหรับระบบ Ubuntu / Debian ที่มีสต็อคdashซึ่งเป็นไปตาม POSIX ด้วยเหตุนี้readคำสั่งจึงไม่สนับสนุน-dสวิตช์ในความแตกต่างอื่น ๆ

ที่จะได้รับรอบนี้มีการแก้ปัญหานี้ซึ่งใช้sleep 1ในสถานที่ของ-dสวิทช์ สิ่งนี้ไม่เหมาะ แต่เสนอวิธีแก้ปัญหาการทำงานอย่างน้อย

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

ตัวอย่าง

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

เชลล์แบบโต้ตอบ

ฉันไม่พบวิธีแก้ปัญหาที่ใช้การได้ซึ่งทำงานได้กับshเชลล์เชิงโต้ตอบเท่านั้น


ดูเหมือนว่าจะใช้ได้เฉพาะกับทุบตีเท่านั้น และไม่ได้อยู่กับดวลจุดโทษ ฉันชอบ sh ดังนั้นฉันจะใช้สิ่งนี้กับดวลจุดโทษได้อย่างไร?
BrainStone

1
@BrainStone - ให้ฉันค้นคว้าและดูว่าฉันไม่สามารถหาวิธี
slm

sh rowcol.sh. ไม่สำคัญว่าคุณใส่อะไรในบรรทัดแรก ( #!/bin/bashหรือ#!/bin/sh) หรือไฟล์ที่ลงท้ายด้วย!
BrainStone

@BrainStone - แต่ผมคิดว่าเป็นเพียงโหมดการทำงานร่วมกันของsh bashเมื่อฉันทำอย่างนั้นsh rowcol.bashมันใช้งานไม่ได้ใช่ไหม?
slm

1
@BrainStone - คุณสามารถสร้างนามแฝงได้alias sh=bashหรือไม่?
slm

17

ใช้-pตัวเลือกแทนechoฉันพบแก้ไขปัญหาการแขวนในสคริปต์ GNU bash, version 3.00.16(1)-release (x86_64-redhat-linux-gnu)ทดสอบกับ

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

ทำงานแบบโต้ตอบหรือในสคริปต์:

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

ขาออก:

$. / cursor.sh
3.00.16 (1) -release
6; 11 6 11
26; 16 26 16

มันใช้งานได้ดีมาก อย่างไรก็ตามน่าเสียดายที่มันไม่ทำงานในกระบวนการพื้นหลังและเมื่อหน้าจอเลื่อนบรรทัดใต้คอลัมน์ที่บันทึกจะเปลี่ยนไป
leondepeon

4

คุณจะได้รับตำแหน่งเคอร์เซอร์ผ่านANSI CSI DSR(สถานะของอุปกรณ์ \e[6nReport): โปรดทราบว่ามันส่งคืนในรูปแบบที่คล้ายกับANSI CSR CUP(ตำแหน่งเคอร์เซอร์) ที่คุณพูดถึงในคำถามของคุณอย่างไรก็ตามมันจะตามหลังแบบฟอร์ม\e[n;mR(โดยที่ n คือแถวและ m คอลัมน์)

รายละเอียดเพิ่มเติมของรหัสหนี ANSI ในวิกิพีเดีย

สำหรับการถือค่าลงในตัวแปรนี้ได้รับการตอบในStackOverflow

ดังที่กล่าวไว้ในคำตอบ / ความคิดเห็นก่อนหน้า (และรายละเอียดในบทความ wikipedia) รหัสเหล่านี้ไม่สามารถพกพาได้เสมอ (จากเทอร์มินัลไปยังเทอร์มินัลและ OS ไปยัง OS) ฉันยังคิดว่านี่จัดการได้ดีกับ termcap / curses;)


และฉันจะเก็บสิ่งนี้ไว้ในตัวแปรได้อย่างไร?
BrainStone

ฉันไม่สามารถทำงานได้ ผมเคยได้รับมีปัญหากับecho -e, และecho -en read ...สิ่งนี้จะเกิดขึ้นเมื่อมีรหัสอยู่ในไฟล์เท่านั้น! ฉันไม่เข้าใจสิ่งนี้จริงๆ!
BrainStone

ดูเหมือนว่าฉันจะทำลายการตั้งค่าบางอย่าง echo -eเคยทำงานมาก่อน แต่ตอนนี้มันไม่ได้! สิ่งที่อาจทำให้เกิดสิ่งนี้และฉันจะคืนค่าได้อย่างไร
BrainStone

2

ด้วยshไวยากรณ์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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.