Bash kullanarak terminaldeki son satır nasıl silinir ve değiştirilir?


102

Bash'de geçen saniyeleri gösteren bir ilerleme çubuğu uygulamak istiyorum. Bunun için, ekranda gösterilen son satırı silmem gerekiyor ("temizle" komutu tüm ekranı siler, ancak sadece ilerleme çubuğunun satırını silmem ve onu yeni bilgilerle değiştirmem gerekiyor).

Nihai sonuç şöyle görünmelidir:

$ Elapsed time 5 seconds

Sonra 10 saniye sonra bu cümleyi (ekrandaki aynı konumda) şu şekilde değiştirmek istiyorum:

$ Elapsed time 15 seconds

Yanıtlar:


117

\ r ile bir satırbaşı yankı yap

seq 1 1000000 | while read i; do echo -en "\r$i"; done

adam yankısından:

-n     do not output the trailing newline
-e     enable interpretation of backslash escapes

\r     carriage return

19
for i in {1..100000}; do echo -en "\r$i"; done
ardışık

Bu tam olarak ihtiyacım olan şeyi yapıyor, teşekkürler !! Ve seq komutunun kullanımı gerçekten de termianl :-) 'yi dondurur
Hata Ayıklayıcı

11
"$ (...) içinde i için" veya "{1..N} içinde i için" gibi şeyler kullandığınızda, tüm öğeleri yinelemeden önce oluşturursunuz, bu büyük girdiler için çok verimsizdir. Ya borulardan yararlanabilirsiniz: "seq 1 100000 | okurken i; do ..." ya da döngü için bash c stilini kullanabilirsiniz: "for ((i = 0 ;; i ++)); do ..."
tokland

Teşekkürler Douglas ve tokland - sekans prodüksiyonu sorunun doğrudan bir parçası olmasa da tokland'ın daha verimli borusuna geçtim
Ken

1
Matris yazıcım kâğıdımı tamamen bozuyor. Artık orada olmayan aynı kağıt parçasında noktalar sıkışmaya devam ediyor, bu program ne kadar çalışıyor?
Rob

188

Satır başı tek başına imleci yalnızca satırın başına taşır. Her yeni çıktı satırı en az bir önceki satır kadar uzunsa sorun değil, ancak yeni satır daha kısaysa, önceki satırın tamamen üzerine yazılmayacaktır, örneğin:

$ echo -e "abcdefghijklmnopqrstuvwxyz\r0123456789"
0123456789klmnopqrstuvwxyz

Yeni metnin satırını gerçekten temizlemek için, aşağıdakilerden \033[Ksonra ekleyebilirsiniz \r:

$ echo -e "abcdefghijklmnopqrstuvwxyz\r\033[K0123456789"
0123456789

http://en.wikipedia.org/wiki/ANSI_escape_code


3
Bu benim çevremde gerçekten iyi çalışıyor. Uyumluluk bilgisi var mı?
Alexander Olsson

21
Bash'de en azından bunun \e[Kyerine kısaltılabilir \033[K.
Dave James Miller

Mükemmel cevap! Ruby'den putlarla mükemmel çalışır. Şimdi araç setimin bir parçası.
phatmann

@ The Pixel Developer: Geliştirmeye çalıştığınız için teşekkürler, ancak düzenlemeniz yanlıştı. Geri dönüş, önce imleci satırın başına hareket ettirmek için gerçekleşmelidir, ardından kill o imleç konumundan sonuna kadar her şeyi temizler ve niyet olan tüm satırı boş bırakır. Bunları Ken'in cevabına benzer şekilde her yeni satırın başına koyarsınız, böylece boş bir satıra yazılır.
Derek Veit

1
Sadece kayıt için, daha önce de \033[Gio yapılabilir, ancak çok daha basittir. Ayrıca görünmez- island.net/xterm/ctlseqs/ctlseqs.html Wikipedia'dan daha fazla ayrıntı verir ve xterm geliştiricisinden alınmıştır. \r\033[K\r
jamadagni

20

Derek Veit'in cevabı, hat uzunluğu hiçbir zaman terminal genişliğini aşmadığı sürece işe yarar. Durum bu değilse, aşağıdaki kod gereksiz çıktıyı önleyecektir:

satır ilk kez yazılmadan önce

tput sc

mevcut imleç konumunu kaydeder. Şimdi, hattınızı ne zaman yazdırmak isterseniz

tput rc
tput ed
echo "your stuff here"

önce kaydedilen imleç konumuna dönmek, ardından ekranı imleçten aşağıya temizlemek ve son olarak çıktıyı yazmak için.


Wierd, bu terminatörde hiçbir şey yapmaz. Uyumluluk sınırlamaları olup olmadığını biliyor musunuz?
Jamie Pate

1
Cygwin için not: "tput" u kullanmak için "ncurses" paketini kurmanız gerekir.
Jack Miller

Hm ... Çıkışta birden fazla satır varsa çalışmıyor gibi görünüyor. Bu işe yaramaz:tput sc # save cursor echo '' > sessions.log.json while [ 1 ]; do curl 'http://localhost/jolokia/read/*:type=Manager,*/activeSessions,maxActiveSessions' >> sessions.log.json echo '' >> sessions.log.json cat sessions.log.json | jq '.' tput rc;tput el # rc = restore cursor, el = erase to end of line sleep 1 done
Nux

@Nux tput edyerine kullanmanız gerekir tput el. @ Um'un örneği kullanıldı ed(belki siz yorum yaptıktan sonra düzeltti).
studgeek

Bilginize, İşte tput komutlarının listesi Renkler ve tput ile İmleç Hareketi
studgeek

13

\ 033 yöntemi benim için işe yaramadı. \ R yöntemi çalışır, ancak aslında hiçbir şeyi silmez, sadece imleci satırın başına koyar. Dolayısıyla, yeni dize eskisinden daha kısaysa, kalan metni satırın sonunda görebilirsiniz. Sonuçta tput, gitmenin en iyi yoluydu. İmleç öğelerinin yanı sıra başka kullanımları da vardır, ayrıca birçok Linux ve BSD dağıtımında önceden yüklenmiş olarak gelir, bu nedenle çoğu bash kullanıcısı için kullanılabilir olmalıdır.

#/bin/bash
tput sc # save cursor
printf "Something that I made up for this string"
sleep 1
tput rc;tput el # rc = restore cursor, el = erase to end of line
printf "Another message for testing"
sleep 1
tput rc;tput el
printf "Yet another one"
sleep 1
tput rc;tput el

İşte oynamak için küçük bir geri sayım betiği:

#!/bin/bash
timeout () {
    tput sc
    time=$1; while [ $time -ge 0 ]; do
        tput rc; tput el
        printf "$2" $time
        ((time--))
        sleep 1
    done
    tput rc; tput ed;
}

timeout 10 "Self-destructing in %s"

Bu gerçekten tüm çizgiyi temizliyor, sorun benim için çok fazla parıldıyor: '(
smarber

5

İlerleme çıktısının çok satırlı olması veya komut dosyasının yeni satır karakterini zaten yazdırması durumunda, aşağıdaki gibi satırları yukarı atlayabilirsiniz:

printf "\033[5A"

bu, imlecin 5 satır yukarı atlamasını sağlar. Daha sonra ihtiyacınız olan her şeyin üzerine yazabilirsiniz.

Bu işe yaramaz Eğer deneyebilirsiniz printf "\e[5A"veya echo -e "\033[5A"aynı etkiye sahip olmalıdır ki,.

Temel olarak, kaçış sekansları ile ekrandaki hemen hemen her şeyi kontrol edebilirsiniz.


Bunun taşınabilir eşdeğeri, tput cuu 55'in satır sayısıdır ( cuuyukarı hareket etmek, cudaşağı hareket etmek ).
Maëlan

4

Satır başı karakterini kullanın:

echo -e "Foo\rBar" # Will print "Bar"

Bu cevap en basit yoldur. Aynı etkiyi şunu kullanarak bile elde edebilirsiniz: printf "Foo \ rBar"
lee8oi

1

Taşıma dönüşü yerleştirerek bunu başarabilir \r.

Tek bir kod satırında printf

for i in {10..1}; do printf "Counting down: $i\r" && sleep 1; done

veya ile echo -ne

for i in {10..1}; do echo -ne "Counting down: $i\r" && sleep 1; done
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.