Hoe verwijder en vervang ik de laatste regel in de terminal met bash?

Ik wil een voortgangsbalk implementeren die de verstreken seconden in bash weergeeft. Hiervoor moet ik de laatste regel op het scherm wissen (de opdracht “wissen” wist het hele scherm, maar ik hoef alleen de regel van de voortgangsbalk te wissen en deze te vervangen door de nieuwe informatie).

Het uiteindelijke resultaat zou er als volgt uit moeten zien:

$ Elapsed time 5 seconds

Na 10 seconden wil ik deze zin (op dezelfde positie in het scherm) vervangen door:

$ Elapsed time 15 seconds

Antwoord 1, autoriteit 100%

De regelterugloop alleen verplaatst de cursor alleen naar het begin van de regel. Dat is OK als elke nieuwe regel met uitvoer minstens zo lang is als de vorige, maar als de nieuwe regel korter is, wordt de vorige regel niet volledig overschreven, bijvoorbeeld:

$ echo -e "abcdefghijklmnopqrstuvwxyz\r0123456789"
0123456789klmnopqrstuvwxyz

Om de regel voor de nieuwe tekst te wissen, kunt u \033[Ktoevoegen na de \r:

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

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


Antwoord 2, autoriteit 59%

echo een regelterugloop met \r

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

van man echo:

-n     do not output the trailing newline
-e     enable interpretation of backslash escapes
\r     carriage return

Antwoord 3, autoriteit 11%

Het antwoord van Derek Veit werkt goed zolang de lijnlengte nooit de terminalbreedte overschrijdt. Als dit niet het geval is, zal de volgende code ongewenste uitvoer voorkomen:

doe voordat de regel voor de eerste keer wordt geschreven

tput sc

die de huidige cursorpositie opslaat. Gebruik nu wanneer u uw regel wilt afdrukken

tput rc
tput ed
echo "your stuff here"

om eerst terug te keren naar de opgeslagen cursorpositie, vervolgens het scherm van de cursor naar beneden te wissen en tenslotte de uitvoer te schrijven.


Antwoord 4, autoriteit 7%

De \033-methode werkte niet voor mij. De \r-methode werkt, maar wist eigenlijk niets, maar zet de cursor gewoon aan het begin van de regel. Dus als de nieuwe string korter is dan de oude, kun je de overgebleven tekst aan het einde van de regel zien. Uiteindelijk was tput de beste manier om te gaan. Het heeft andere toepassingen dan de cursor-dingen en het is vooraf geïnstalleerd in veel Linux & BSD-distributies, dus het zou voor de meeste bash-gebruikers beschikbaar moeten zijn.

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

Hier is een klein aftelscript om mee te spelen:

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

Antwoord 5, autoriteit 5%

In het geval dat de voortgangsuitvoer uit meerdere regels bestaat, of als het script het nieuwe regelteken al zou hebben afgedrukt, kunt u regels omhoog springen met zoiets als:

printf "\033[5A"

waardoor de cursor 5 regels omhoog springt. Daarna kun je alles overschrijven wat je nodig hebt.

Als dat niet zou werken, zou je printf "\e[5A"of echo -e "\033[5A"kunnen proberen, wat hetzelfde effect zou moeten hebben .

Kortom, met escape-reeksenkun je bijna alles besturen op het scherm.


Antwoord 6, autoriteit 2%

Gebruik het terugloopteken:

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

Antwoord 7

Kan dit bereiken door een regelterugloop \rte plaatsen.

In een enkele regel code met printf

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

of met echo -ne

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

Other episodes