ป้องกันไม่ให้ข้อความ / หน้าจอกระพริบเมื่อทำชัดเจน


11

สคริปต์ของฉันทำสิ่งที่ชอบ:

while :;
   clear

   do_a_lot_of_output_here

   sleep 1
done

มันเป็นตัวเลือกใด ๆ เพื่อป้องกันหน้าจอกระพริบเมื่อฉันทำชัดเจนและส่งออก? ฉันต้องการที่จะทำมันเหมือนในwatchคำสั่ง (แต่มันเขียนไว้ในC) คำแนะนำใด ๆ

clear | hexdump -C

00000000  1b 5b 48 1b 5b 32 4a                              |.[H.[2J|
00000007

PS ฉันใช้bashเท่านั้น


คุณสามารถเพิ่มเอาท์พุทของคุณclear | hexdump -C?
ott--

ฉันขยายคำถาม
ravnur

ฉันพบวิธีแก้ไขปัญหาอื่นในstackoverflow.com/questions/5367068/… - echo -en "\ec"แฟลชอีกด้วยหรือไม่
ott--

ฉันก็เจออันนี้เหมือนกัน ทั้งสองรุ่นต่างจากแฟลชคำตอบด้วยเช่นกัน
ravnur

ฉันประสบความสำเร็จกับเครื่องมือนี้: overd.org/article/2009/07/watch1-bash-unicode
raine

คำตอบ:


8

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

นี่คือตัวอย่าง:

#!/bin/sh
watchit() {
    HOME=$(tput cup 0 0)
    ED=$(tput ed)
    EL=$(tput el)
    ROWS=$(tput lines)
    COLS=$(tput cols)
    printf '%s%s' "$HOME" "$ED"
    while true
    do
        CMD="$@"
        ${SHELL:=sh} -c "$CMD" | head -n $ROWS | while IFS= read LINE; do
            printf '%-*.*s%s\n' $COLS $COLS "$LINE" "$EL"
        done
        printf '%s%s' "$ED" "$HOME"
        sleep 1
    done
}

watchit top -b -n 1

มันทำสิ่งนี้:

  • พิมพ์เอาต์พุตจากคำสั่งที่กำหนดซึ่งจะพอดีกับหน้าจอ (ไม่มีการตัดหรือเลื่อน)
  • เขียนบนบรรทัดที่มีอยู่การล้างส่วนของแต่ละบรรทัดที่ไม่ถูกเขียนทับ
  • ใช้edความสามารถของเทอร์มินัลของคุณเพื่อพิมพ์จากตำแหน่งปัจจุบันไปยังจุดสิ้นสุดของหน้าจอ

หากคุณต้องการจัดการหน้าจอที่ปรับขนาดได้คุณสามารถย้ายการมอบหมายไปยังROWSและCOLSภายในลูปด้านนอกเช่น

#!/bin/sh
watchit() {
    HOME=$(tput cup 0 0)
    ED=$(tput ed)
    EL=$(tput el)
    printf '%s%s' "$HOME" "$ED"
    while true
    do
        ROWS=$(tput lines)
        COLS=$(tput cols)
        CMD="$@"
        ${SHELL:=sh} -c "$CMD" | head -n $ROWS | while IFS= read LINE; do
            printf '%-*.*s%s\n' $COLS $COLS "$LINE" "$EL"
        done
        printf '%s%s' "$ED" "$HOME"
        sleep 1
    done
}

watchit top -b -n 1

เพราะtputขอหน้าจอปัจจุบันจากระบบ

อ่านเพิ่มเติม:


1
สำหรับผู้ที่ใช้#!/bin/bashและต้องการที่จะใช้ฝังตัวอยู่ในสคริปต์แบบสแตนด์อะโลนขนาดเล็กที่มีฟังก์ชั่นบางอย่างที่คุณสามารถทำได้watchit export -f function_name; watchit function_name
รวม

สิ่งนี้ทำงานได้อย่างสมบูรณ์แบบสำหรับฉันยกเว้นว่าฉันเจอปัญหาตลก ๆ ที่ด้านบนของหน้าจอซึ่งสิ่งต่าง ๆ จะเปลี่ยนไปและมีความผิดปกติสำหรับข้อความที่ยาวheadขึ้น ดูเหมือนว่าปัญหานี้เป็นข้อผิดพลาดแบบหนึ่งต่อหนึ่ง (อย่างน้อยในการตั้งค่าของฉัน - เซสชัน ssh ในบานหน้าต่างแยก iTerm2) เมื่อคำนวณจำนวนแถว ROWS=`expr $(tput lines) - 1`พูดได้อย่างสมบูรณ์แบบนี้
ohruunuruus

นี่มันวิเศษมากขอบคุณมาก @ thomas-dickey
mbarkhau

9

วิธีหนึ่งที่จะช่วยป้องกันการกระพริบคือการเอาท์พุททั้งหมดก่อนที่จะทำการล้างหน้าจอเพื่อให้มีเวลาน้อยที่สุดระหว่างการล้างและการวาดใหม่ สิ่งนี้คล้ายกับแนวคิดของการบัฟเฟอร์สองเท่า:

while :; do
   output=$(do_a_lot_of_output_here)
   clear
   echo "$output"
   sleep 1
done

สิ่งนี้ไม่ได้เป็นการกำจัดการสั่นสะเทือนทั้งหมด แต่มันก็เกิดขึ้นน้อยมากในประสบการณ์ของฉัน


การบัฟเฟอร์สองครั้งเช่นเดียวกับในสถานการณ์อื่น ๆ ทำให้ปลอดภัยทั้งวัน :-)
Ikke

ทำงานเหมือนจับใจ ไม่มีการกระพริบเลย :)
Lars Juel Jensen

1
ริบหรี่ที่เหลือก็จะถูกกำจัดโดยรวมลงในบัฟเฟอร์คือclear output=$(clear; do_a_lot_of_output_here)
kdb

@kdb คำแนะนำที่ดี! สิ่งนี้เกือบจะกำจัดริบหรี่สำหรับฉันและทำได้ง่ายกว่าคำตอบที่ยอมรับ
Michael Mior

งานนี้มีเสน่ห์เหมือนกัน! ตอนแรกฉันพลาดเครื่องหมายคำพูดคู่ใน 'echo "$ output"' และจากนั้นเส้นก็จะมั่วไปหมด (พื้นที่ว่างทั้งหมดถือเป็นช่องว่างเดียว)
ป๊อปอัป

5

การกะพริบเป็นผลที่ไม่สามารถหลีกเลี่ยงได้ของการล้างหน้าจอในแต่ละรอบลูป คุณสามารถเลื่อนเคอร์เซอร์ไปที่ด้านบนของหน้าจอและเขียนทับส่วนต่าง ๆ ของผลลัพธ์เดิมของคุณแทน

# You may want to do this if your code is in a script.
unhide_cursor() {
    printf '\e[?25h'
}
trap unhide_cursor EXIT

# Hide the cursor (there is probably a much better way to do this)
printf '\e[?25l'
clear 
while true ; do
    # Move the cursor to the top of the screen but don't clear the screen
    printf '\033[;H' 
    do_a_lot_of_output_here
    sleep 1
done

สคริปต์นี้จะปล่อยให้สิ่งประดิษฐ์ถ้าผลลัพธ์ของคุณหดตัว มันก็ไม่น่าจะพกพาได้ ฉันทดสอบด้วย urxvt, xterm และ st เท่านั้น


ในกรณีนี้เคอร์เซอร์จะเริ่มกระโดดไปที่จุดสิ้นสุดของการส่งออกจากตำแหน่งสุ่ม (และสิ่งประดิษฐ์ของหลักสูตร) นอกจากนี้ฉันพยายามtput clearด้วยผลลัพธ์เดียวกัน (กระพริบตา)
ravnur

ฉันเพิ่มสองสามบรรทัดในสคริปต์เพื่อซ่อนเคอร์เซอร์

ไม่มีเคอร์เซอร์ - ไม่ต้องกระโดด แต่เกี่ยวกับสิ่งประดิษฐ์? ผลลัพธ์มีจำนวนแถวสุ่ม ฉันต้องกรอกสคริปต์ทั้งหมดด้วยช่องว่างก่อนที่จะเริ่มเอาต์พุตใหม่หรือไม่ แต่อย่างไรก็ตามขอบคุณสำหรับเวลาและความพยายามของคุณ: +1 จากฉันสำหรับสิ่งนั้น แต่มันไม่สามารถแก้ปัญหาของฉันได้
ravnur

ฉันพบวิธีเดียวเท่านั้นที่จะกำจัดสิ่งประดิษฐ์ทั้งหมด: tput ed. แต่มันก็ทำให้กระพริบ
ravnur

คุณใช้เทอร์มินัลอีมูเลเตอร์ใด? ด้วยtput edขวาก่อนdo_a_lot...บรรทัดฉันเห็นกะพริบเป็น urxvt แต่ไม่ใช่ xterm หรือ st

1

ในฐานะที่เป็นส่วนขยายของคำตอบของ Cristian ฉันได้ทำฟังก์ชั่นทุบตีต่อไปนี้ซึ่งใช้งานได้หากหน้าต่างคอนโซลมีขนาดเล็กกว่าเอาท์พุทของคำสั่ง:

function watcher()
{
    lines=$(tput lines)
    while true; do
        output="$($@ | head -n $lines)"
        clear
        echo -e "$output"
        sleep 2
    done
}

สิ่งนี้อนุญาตให้คุณส่งคำสั่งใด ๆ ไปยังผู้เฝ้าดู หากคุณใช้คอมไพล์ให้ใช้git config --global color.status alwaysแล้ว:

watcher git status

จะแสดงผลลัพธ์สถานะ git ที่อัปเดตตลอดเวลา

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