Podczas wykonywania skryptów w bash lub innej powłoce w * NIX, podczas uruchamiania polecenia, które zajmie więcej niż kilka sekund, potrzebny jest pasek postępu.
Na przykład, kopiowanie dużego pliku, otwieranie dużego pliku tar.
W jaki sposób zaleca się dodawanie pasków postępu do skryptów powłoki?
Odpowiedzi:
Możesz to zaimplementować, nadpisując linię. Użyj,
\r
aby wrócić do początku linii bez pisania\n
na terminalu.Napisz,
\n
kiedy skończysz, aby przejść dalej.Użyj
echo -ne
do:\n
i\r
.Oto demo:
W komentarzu poniżej puk wspomina, że „to się nie udaje”, jeśli zaczynasz od długiej linii, a następnie chcesz napisać krótką linię: W takim przypadku musisz zastąpić długość długiej linii (np. Spacjami).
źródło
printf
zamiastecho
.printf "#### (50%%)\r"
nie działałoby to z pojedynczymi cudzysłowami, a znak procentu musi być poprzedzony znakiem ucieczki.Możesz być także zainteresowany tym, jak zrobić spinner :
Czy mogę zrobić spinner w Bash?
źródło
while :;do for s in / - \\ \|; do printf "\r$s";sleep .1;done;done
(*:sleep
może wymagać znaków ints, a nie miejsc po przecinku)some_work ...
powyższej linii; bardziej szczegółową dyskusję opartą na tej pomocnej odpowiedzi i pomocnym komentarzu Adama Katza - z naciskiem na zgodność z POSIX - można znaleźć tutaj .\b
zamiast\r
, ponieważ w przeciwnym razie będzie działał tylko na samym początku linii:while :; do for c in / - \\ \|; do printf '%s\b' "$c"; sleep 1; done; done
- lub, jeśli wyświetla kursor za pokrętłem jest niepożądany:printf ' ' && while :; do for c in / - \\ \|; do printf '\b%s' "$c"; sleep 1; done; done
job=$!
), a następnie uruchomićwhile kill -0 $job 2>/dev/null;do …
na przykład:sleep 15 & job=$!; while kill -0 $job 2>/dev/null; do for s in / - \\ \|; do printf "\r$s"; sleep .1; done; done
Niektóre posty pokazały, jak wyświetlić postęp polecenia. Aby to obliczyć, musisz zobaczyć, ile osiągnąłeś. W systemach BSD niektóre polecenia, takie jak dd (1), akceptują
SIGINFO
sygnał i zgłaszają swoje postępy. W systemach Linux niektóre polecenia będą reagować podobnieSIGUSR1
. Jeśli ta funkcja jest dostępna, możesz przesyłać dane wejściowe wdd
celu monitorowania liczby przetworzonych bajtów.Alternatywnie można użyć
lsof
do uzyskania przesunięcia wskaźnika odczytu pliku, a tym samym do obliczenia postępu. Napisałem polecenie o nazwie pmonitor , które wyświetla postęp przetwarzania określonego procesu lub pliku. Dzięki niemu możesz wykonywać następujące czynności:Na moim blogu pojawia się wcześniejsza wersja skryptów powłoki Linux i FreeBSD .
źródło
awk
grasz!Mam łatwą funkcję paska postępu, którą napisałem poprzedniego dnia:
Lub złap go,
https://github.com/fearside/ProgressBar/
źródło
printf "\rProgress : [${_fill// /▇}${_empty// / }] ${_progress}%%"
użyj komendy linux pv:
http://linux.die.net/man/1/pv
nie zna rozmiaru, jeśli znajduje się w środku strumienia, ale daje prędkość i sumę, a stamtąd możesz dowiedzieć się, jak długo to potrwa i uzyskać informacje zwrotne, aby wiedzieć, że nie zawiesił się.
źródło
Szukałem czegoś bardziej seksownego niż wybrana odpowiedź, podobnie jak mój własny scenariusz.
Zapowiedź
Źródło
Włożyłem to na github
progress-bar.sh
Stosowanie
źródło
progress-bar 100
GNU tar ma przydatną opcję, która daje funkcjonalność prostego paska postępu.
(...) Kolejną dostępną akcją punktu kontrolnego jest „kropka” (lub „.”). Poleca tarowi wydrukowanie pojedynczej kropki na standardowym strumieniu listowania, np .:
Ten sam efekt można uzyskać poprzez:
źródło
--checkpoint=.10
. Działa również świetnie podczas ekstrakcjitar -xz
.Prostsza metoda, która działa w moim systemie za pomocą narzędzia pipeview (pv).
źródło
Nie widziałem nic podobnego, a wszystkie niestandardowe funkcje wydają się koncentrować na samym renderowaniu, więc ... moje bardzo proste rozwiązanie zgodne z POSIX poniżej z objaśnieniami krok po kroku, ponieważ to pytanie nie jest trywialne.
TL; DR
Renderowanie paska postępu jest bardzo łatwe. Szacowanie, ile z tego powinno się renderować, to inna sprawa. Oto jak renderować (animować) pasek postępu - możesz skopiować i wkleić ten przykład do pliku i uruchomić go:
{1..20}
- wartości od 1 do 20echo -n
- drukuj bez nowej linii na końcuecho -e
- interpretować znaki specjalne podczas drukowania"\r"
- powrót karetki, specjalny znak powrotu do początku liniiMożesz sprawić, że będzie renderować dowolną zawartość przy dowolnej prędkości, więc ta metoda jest bardzo uniwersalna, np. Często używana do wizualizacji „hakowania” w niemądrych filmach, bez żartów.
Pełna odpowiedź
Istotą problemu jest to, jak określić
$i
wartość, tj. Jaka część paska postępu ma zostać wyświetlona. W powyższym przykładzie po prostu pozwoliłem inkrementacji wfor
pętli, aby zilustrować zasadę, ale aplikacja z prawdziwego życia użyłaby nieskończonej pętli i obliczyłaby$i
zmienną przy każdej iteracji. Do wykonania wspomnianych obliczeń potrzebne są następujące składniki:W razie
cp
potrzeby rozmiar pliku źródłowego i rozmiar pliku docelowego:stat
- sprawdź statystyki pliku-c
- zwraca sformatowaną wartość%s
- całkowity rozmiarW przypadku operacji takich jak rozpakowywanie pliku, obliczenie rozmiaru źródła jest nieco trudniejsze, ale nadal tak proste, jak uzyskanie rozmiaru nieskompresowanego pliku:
gzip -l
- wyświetla informacje o archiwum ziptail -n1
- praca z 1 linią od dołutr -s ' '
- przetłumacz wiele spacji na jeden (ściśnij je)cut -d' ' -f3
- wytnij 3. rozdzielaną spacjami kolumnęOto sedno problemu. To rozwiązanie jest coraz mniej ogólne. Wszystkie obliczenia rzeczywistego postępu są ściśle powiązane z domeną, którą próbujesz sobie wyobrazić, czy jest to pojedyncza operacja na pliku, odliczanie czasu, rosnąca liczba plików w katalogu, operacja na wielu plikach itp., Dlatego nie można ponownie użyć. Jedyną częścią wielokrotnego użytku jest renderowanie paska postępu. Aby go ponownie użyć, musisz go wyodrębnić i zapisać w pliku (np.
/usr/lib/progress_bar.sh
), A następnie zdefiniować funkcje, które obliczają wartości wejściowe specyficzne dla Twojej domeny. Tak mógłby wyglądać uogólniony kod (wprowadziłem też$BAR
dynamikę, ponieważ ludzie o to prosili, reszta powinna być teraz jasna):printf
- wbudowane do drukowania rzeczy w danym formacieprintf '%50s'
- nic nie drukuj, wypełnij go 50 spacjamitr ' ' '#'
- przetłumacz każdą spację na znak skrótuI tak byś tego użył:
Oczywiście może być zawinięty w funkcję, przepisany do pracy z potokami strumieniowymi, przepisany na inny język, bez względu na twoją truciznę.
źródło
Chciałbym również wnieść własny pasek postępu
Osiąga precyzję podznakową za pomocą bloków Half unicode
Kod jest zawarty
źródło
Pasek postępu w stylu APT (nie psuje normalnej wydajności)
EDYCJA: Aby uzyskać zaktualizowaną wersję, sprawdź moją stronę github
Odpowiedzi na to pytanie nie były satysfakcjonujące. To, czego osobiście szukałem, to fantazyjny pasek postępu, jak widzi APT.
Rzuciłem okiem na kod źródłowy C dla APT i postanowiłem napisać własny odpowiednik dla bash.
Pasek postępu pozostanie ładnie na dole terminala i nie będzie zakłócał żadnego wyjścia wysyłanego do terminala.
Należy pamiętać, że pasek jest obecnie ustawiony na szerokość 100 znaków. Jeśli chcesz przeskalować go do rozmiaru terminala, jest to również dość łatwe do osiągnięcia (zaktualizowana wersja na mojej stronie github dobrze sobie z tym radzi).
Tutaj opublikuję mój skrypt. Przykład użycia:
Skrypt (zdecydowanie zalecam wersję na moim githubie):
źródło
Umożliwia to wizualizację, że polecenie jest nadal wykonywane:
Spowoduje to utworzenie nieskończonej pętli while, która będzie działać w tle i wywoła echo „.” każda sekunda. To wyświetli się
.
w powłoce. Uruchomtar
polecenie lub dowolne polecenie. Po zakończeniu wykonywania tego polecenia zabij ostatnie zadanie działające w tle - czyli nieskończoną pętlę while .źródło
Oto jak może to wyglądać
Przesyłanie pliku
Oczekiwanie na zakończenie zadania
Prosta funkcja, która to implementuje
Możesz po prostu skopiować i wkleić go do skryptu. Nie wymaga niczego innego do działania.
Przykład użycia
Tutaj przesyłamy plik i przerysowujemy pasek postępu przy każdej iteracji. Nie ma znaczenia, jakie zadanie jest faktycznie wykonywane, o ile możemy uzyskać 2 wartości: wartość maksymalną i wartość bieżącą.
W poniższym przykładzie maksymalna wartość to,
file_size
a bieżąca wartość jest dostarczana przez jakąś funkcję i jest wywoływanauploaded_bytes
.źródło
Większość poleceń uniksowych nie daje ci takiej bezpośredniej informacji zwrotnej, z której możesz to zrobić. Niektóre dadzą ci wyjście na stdout lub stderr, których możesz użyć.
W przypadku czegoś takiego jak tar można użyć przełącznika -v i potokować dane wyjściowe do programu, który aktualizuje małą animację dla każdego czytanego wiersza. Gdy tar wypisuje listę plików, jest to rozwikłane, program może zaktualizować animację. Aby wykonać procent ukończenia, musisz znać liczbę plików i policzyć wiersze.
cp nie daje tego rodzaju danych wyjściowych, o ile mi wiadomo. Aby monitorować postęp cp, musisz monitorować pliki źródłowe i docelowe oraz obserwować rozmiar miejsca docelowego. Możesz napisać mały program c przy użyciu wywołania systemowego stat (2) , aby uzyskać rozmiar pliku. Odczytuje to rozmiar źródła, a następnie sonduje plik docelowy i aktualizuje pasek% complete na podstawie rozmiaru zapisanego do tej pory pliku.
źródło
Moje rozwiązanie wyświetla procent tarballa, który jest obecnie rozpakowywany i zapisywany. Używam tego podczas zapisywania obrazów głównego systemu plików o wielkości 2 GB. Naprawdę potrzebujesz paska postępu dla tych rzeczy. To, co robię, służy
gzip --list
do uzyskania całkowitego nieskompresowanego rozmiaru archiwum. Na tej podstawie obliczam współczynnik blokowania potrzebny do podzielenia pliku na 100 części. Na koniec drukuję komunikat punktu kontrolnego dla każdego bloku. W przypadku pliku 2 GB daje to około 10 MB bloku. Jeśli jest to zbyt duże, możesz podzielić BLOCKING_FACTOR przez 10 lub 100, ale wtedy trudniej jest wydrukować ładne wyniki w procentach.Zakładając, że używasz Bash, możesz użyć następującej funkcji powłoki
źródło
Po pierwsze, pasek nie jest jedynym miernikiem postępu rur. Drugi (może nawet bardziej znany) to pv (przeglądarka potoków).
Po drugie, bar i pv mogą być używane na przykład w następujący sposób:
lub nawet:
jedną przydatną sztuczką, jeśli chcesz użyć bar i pv w komendach, które działają z plikami podanymi w argumentach, np. kopiuj plik1 plik2, jest użycie podstawienia procesu :
Podstawianie procesów to bashowa magia, która tworzy tymczasowe pliki potoków FIFO / dev / fd / i łączy stdout z uruchomionego procesu (w nawiasach) przez ten potok i kopiuje traktuje go jak zwykły plik (z jednym wyjątkiem, może go tylko odczytać do przodu).
Aktualizacja:
samo polecenie bar pozwala również na kopiowanie. Po pasku man:
Ale moim zdaniem podstawianie procesów jest bardziej ogólne. Używa samego programu cp.
źródło
Wolę używać okna dialogowego z parametrem --gauge . Jest bardzo często używany w instalacjach pakietów .deb i innych podstawowych elementach konfiguracyjnych wielu dystrybucji. Więc nie musisz wymyślać koła ponownie ... ponownie
Wystarczy podać wartość int od 1 do 100 @stdin. Jeden podstawowy i głupi przykład:
Mam ten plik / bin / Wait (z chmod u + x perms) do gotowania: P
Mogę więc umieścić:
Wait "34 min" "warm up the oven"
lub
Wait "dec 31" "happy new year"
źródło
dla mnie najłatwiejszym w użyciu i jak dotąd najlepiej wyglądającym jest polecenie
pv
lubbar
jak jakiś facet już napisałna przykład: trzeba wykonać kopię zapasową całego dysku za pomocą
dd
zwykle używasz
dd if="$input_drive_path" of="$output_file_path"
z
pv
tobą możesz to zrobić tak:dd if="$input_drive_path" | pv | dd of="$output_file_path"
a postęp idzie bezpośrednio do
STDOUT
tego:po zakończeniu pojawi się podsumowanie
źródło
pv
lubbar
wizualizować postęp różnych procesów, np. Odliczanie czasu, pozycję w pliku tekstowym, instalację aplikacji, konfigurację środowiska uruchomieniowego itp.?Wiele odpowiedzi opisuje pisanie własnych poleceń do wydrukowania
'\r' + $some_sort_of_progress_msg
. Problem czasami polega na tym, że wydrukowanie setek takich aktualizacji na sekundę spowolni proces.Jeśli jednak któryś z twoich procesów generuje dane wyjściowe (np. Wyświetli
7z a -r newZipFile myFolder
każdą nazwę pliku podczas kompresji), istnieje prostsze, szybkie, bezbolesne i konfigurowalne rozwiązanie.Zainstaluj moduł python
tqdm
.Pomoc:
tqdm -h
. Przykład z większą liczbą opcji:Jako bonus można także wykorzystać
tqdm
do zawijania iterable w kodzie Pythona.https://github.com/tqdm/tqdm/blob/master/README.rst#module
źródło
tqdm
STDOUTwc -l
przez rurę. Prawdopodobnie chcesz od tego uciec.tqdm
pokaże postępSTDERR
podczas przesyłania danych wejściowychSTDIN
doSTDOUT
. W takim przypadkuwc -l
otrzymalibyśmy takie same dane wejściowe, jakbytqdm
nie zostały uwzględnione.Na podstawie pracy Edouarda Lopeza stworzyłem pasek postępu, który pasuje do wielkości ekranu, cokolwiek to jest. Sprawdź to.
Jest także opublikowany w Git Hub .
Cieszyć się
źródło
https://github.com/extensionsapp/progre.sh
Utwórz 40 procent postępu:
progreSh 40
źródło
Ma to zastosowanie tylko przy użyciu zenity gnome. Zenity zapewnia świetny natywny interfejs do skryptów bash: https://help.gnome.org/users/zenity/stable/
Z paska postępu Zenity Przykład:
źródło
Użyłem odpowiedzi z sekcji Tworzenie ciągu powtarzających się znaków w skrypcie powłoki do powtarzania znaków . Mam dwie stosunkowo małe wersje bash dla skryptów, które muszą wyświetlać pasek postępu (na przykład pętla, która przechodzi przez wiele plików, ale nie jest przydatna w przypadku dużych plików tar lub operacji kopiowania). Szybsza składa się z dwóch funkcji, z których jedna służy do przygotowania ciągów do wyświetlania słupkowego:
i jeden, aby wyświetlić pasek postępu:
Może być używany jako:
co oznacza przygotowanie ciągów dla paska ze 50 znakami „#”, a następnie:
wyświetli liczbę znaków „#” odpowiadającą proporcji 35/80:
Należy pamiętać, że funkcja wyświetla pasek w kółko w tej samej linii, dopóki ty (lub inny program) nie wydrukujesz nowej linii. Jeśli jako pierwszy parametr podasz -1, pasek zostanie usunięty:
Wolniejsza wersja ma jedną funkcję:
i może być użyty jako (ten sam przykład jak powyżej):
Jeśli potrzebujesz paska postępu na stderr, po prostu dodaj
>&2
na końcu każdego polecenia printf.źródło
Aby wskazać postęp aktywności, wypróbuj następujące polecenia:
LUB
LUB
LUB
Można użyć flag / zmiennych wewnątrz pętli while, aby sprawdzić i wyświetlić wartość / zakres postępu.
źródło
Korzystając z wyżej wymienionych sugestii, zdecydowałem się zaimplementować własny pasek postępu.
źródło
percent_none="$(( 100 - "$percent_done" ))"
napercent_none="$(( 100 - $percent_done))"
Zrobiłem czystą wersję powłoki dla systemu osadzonego, wykorzystując:
Funkcja obsługi sygnału SIGUSR1 w / usr / bin / dd.
Zasadniczo, jeśli wyślesz polecenie „kill SIGUSR1 $ (pid_of_running_dd_process)”, wyświetli ono podsumowanie prędkości transmisji i przesłanej kwoty.
uruchamianie w tle dd, a następnie regularne sprawdzanie go w poszukiwaniu aktualizacji i generowanie znaczników skrótu, takich jak dawni klienci ftp.
Używanie / dev / stdout jako miejsca docelowego dla programów sprzyjających innym standardom, takich jak scp
Wynik końcowy pozwala wykonać dowolną operację przesyłania plików i uzyskać aktualizację postępu, która wygląda jak dane wyjściowe „haszowania” starej szkoły FTP, w których po prostu uzyskasz znak krzyżyka dla każdego X bajtów.
To nie jest kod jakości produkcji, ale masz pomysł. Myślę, że to słodkie.
Rzeczywista liczba bajtów może być niepoprawnie odzwierciedlona w liczbie skrótów - w zależności od problemów z zaokrąglaniem może być ich więcej lub mniej. Nie używaj tego jako części skryptu testowego, to po prostu cukierki. I tak, wiem, że jest to strasznie nieefektywne - to skrypt powłoki i nie przepraszam za to.
Przykłady z wget, scp i tftp na końcu. Powinien działać ze wszystkim, co emituje dane. Upewnij się, że używasz / dev / stdout dla programów, które nie są przyjazne stdout.
Przykłady:
źródło
pidof dd
jest przerażające.$!
oddd
i czekać na[[ -e /proc/${DD_PID} ]]
.Jeśli musisz pokazać pasek postępu czasowego (znając wcześniej czas wyświetlania), możesz użyć Pythona w następujący sposób:
Następnie, zakładając, że zapisałeś skrypt Python jako
progressbar.py
, możliwe jest wyświetlenie paska postępu ze skryptu bash, uruchamiając następującą komendę:Pokazuje
50
znaki wielkości paska postępu i „biegnie” przez10
kilka sekund.źródło
Oparłem się na odpowiedzi udzielonej przez strach
Łączy się to z bazą danych Oracle w celu pobrania postępu przywracania RMAN.
źródło
mógłby stworzyć funkcję, która rysuje to w skali, powiedzmy 1-10 dla liczby pasków:
źródło
wynik:
Uwaga: jeśli zamiast 255 wstawisz 1, będziesz monitorować standard w ... z 2 standardem na wyjściu (ale musisz zmodyfikować źródło, aby ustawić „tot” na wielkość wyświetlanego pliku wyjściowego)
źródło