[bash] wget - pętla w nagrywaniu audycji

Na wstępie zaznaczę, że na programowaniu nie znam się w ogóle, a skrypt, o który pytam, znalazłem w necie i tylko dostosowałem go do swoich potrzeb na zasadzie domysłów.
Przy użyciu konta shell i crona nagrywam codziennie audycje. Robię to przy użyciu takiego oto skryptu:

 

#!/bin/bash

DATA=`date +%Y-%m-%d-godz-%H:%M:%S`

NAZWAPLIKU=$DATA"-pr4"

wget http://stream3.polskieradio.pl:8906 -O /usr/home/Rostov/pr4/$NAZWAPLIKU.mp3 -o usr/home/Rostov/pr4/log/$NAZWAPLIKU.log

 

Niestety, ze streamem są częste kłopoty i bardzo często staje się on niedostępny (komunikat w logu: ‘Żądanie HTTP wysłano, oczekiwanie na odpowiedź… 404 File Not Found’), wskutek czego nagrywanie zostaje przerwane i nie jest już wznawiane. Chciałbym, aby po zerwaniu połączenia skrypt natychmiast ponawiał łączenie ze streamem dotąd, dopóki nie będzie on znów dostępny i kontynuował nagrywanie do tego samego pliku. Jak powinien wyglądać taki skrypt?

#!/bin/bash



while [1]; do

	DATA=`date +%Y-%m-%d-godz-%H:%M:%S`

	NAZWAPLIKU=$DATA"-pr4"

	wget http://stream3.polskieradio.pl:8906 -O /usr/home/Rostov/pr4/$NAZWAPLIKU.mp3 -o usr/home/Rostov/pr4/log/$NAZWAPLIKU.log

	sleep 5

done

W nieskończonej pętli będzie wykonywał te same czynności. Po przerwanym streamie zrobi 5 sekund przerwy przed próbą nagrania kolejnego. Po przerwanym streamie w tym wypadku utworzy nowy plik MP3.

 

Ale widzę inny problem. Piszesz o tym, że uruchamiasz skrypt z crona. Ale jeśli ustawisz w cronie uruchamianie codziennie, to codziennie nowy skrypt rozpocznie nagrywanie, podczas gdy kolejny go nie skończy. Przewidziałeś taką sytuację?

Nie dopowiedziałem, że zatrzymuję nagrywanie o wybranej godzinie innym skryptem, który działa poprawnie. :slight_smile:

 

Czy można zmniejszyć czas przerwy przed podjęciem próby kolejnego nagrywania do 1 sekundy?

Czy można kontynuować nagrywanie do tego samego pliku, którego nagrywanie zostało przerwane?

 

czasami jest dobrze wpisać “wget --help” :slight_smile:

 

 

Rozumiem, że przy użyciu tych komend rozwiązanie podane przez ra-v nie mają zastosowania i skrypt powinien wyglądać tak?

 

#!/bin/bash

	DATA=`date +%Y-%m-%d-godz-%H:%M:%S`

	NAZWAPLIKU=$DATA"-pr4"

	wget http://stream3.polskieradio.pl:8906 -O --waitretry=1 --no-clobber --continue --tries=0 /usr/home/Rostov/pr4/$NAZWAPLIKU.mp3 -o usr/home/Rostov/pr4/log/$NAZWAPLIKU.log

done

Przepraszam za tak banalne pytania, ale zupełnie nie znam języka bash i jego składni. Wszystko wymyślam w oparciu o analogie.

 

A może tak?

 

#!/bin/bash



	DATA=`date +%Y-%m-%d-godz-%H:%M:%S`



	NAZWAPLIKU=$DATA"-pr4"



	wget --waitretry=1 --no-clobber --continue --tries=0 http://stream3.polskieradio.pl:8906 -O /usr/home/Rostov/pr4/$NAZWAPLIKU.mp3 -o usr/home/Rostov/pr4/log/$NAZWAPLIKU.log



done

 

Bo chyba jednak te opcje dotyczą linka.

Dobrze - powinno zadziałać.

Te opcje dotyczą pobierania.

Zerwij sobie połączenie w trakcie pobierania to zobaczysz, czy wznowi po ponownym połączeniu.

 

Na co dzień używam Windowsa, a nie wiem, jak to zrobić na shellu. Chyba dowiem się dopiero, gdy zdarzy się przypadek przerwania streamu. :slight_smile:

Pozwolę sobie dopytać o jeszcze jedną rzecz. Skrypt nagrywa bez zarzutu. Jednak gdy testuję go na koncie shell, po zalogowaniu przez Putty, tzn. uruchamiam go komendą:

sh nazwaskryptu.sh

kursor przechodzi mi do nowego wiersza i znika znak zachęty, tzn. nie mogę wpisać nawet ‘logout’, by wyjść z terminala. Tzn. wpisać mogę, ale po wciśnięciu Entera nie dzieje się nic. Co może być tego przyczyną?

Gdy w ten sam sposób uruchamiam skrypt, którym zatrzymuję nagrywanie:

#!/bin/bash

killall -9 wget

po wciśnięciu Entera znak zachęty pojawia się na nowo.

Znak zachęty powróci w momencie gdy zakończy się wykonywanie skryptu. Odpal sobie 2 razy putty w jednym oknie uruchom pierwszy skrypt, w drugi go zatrzymaj, w pierwszym oknie powinieneś znów mieć znak zachęty.
Dzieje się tak z tego powodu że skrypt działa w nieskończonej pętli. Aby móc go tak uruchomić i dalej pracować powinieneś uruchomić go w tle screenem albo stworzyć dla niego service i uruchomić go jako usługę (service nazwaskryptu start|stop). Zależnie od dystrybucji i tego jaki program inicjalizujący masz zainstalowany może to wyglądać inaczej, albo tworzysz skrypt w /etc/init.d z obsługą poleceń start stop, albo odpowiedni plik konfiguracyjny dla systemd w /etc/systemd/cos_tam_nie_pamiętam.

sh -c ./nazwaskryptu.sh &

Spowoduje uruchomienie w tle. Ale nie będziesz mógł przerwać jego działania np. naciskając Ctrl+C.
Do pętli, które coś ciągle wypisują się nie nadaje.

Można też przekierować wyjście skryptu do NULL, aby się uruchomił, ale nic nie wyświetlał.

sh -c ./nazwaskryptu.sh > /dev/null 2>&1 &

Kończysz jego pracę:

killall -3 nazwaskryptu.sh

(-3 -> ponieważ to nie jest ubicie procesu tylko jego zakończenie)

Zamiast do NULL możesz też przekierować wyjście do pliku:

sh -c ./nazwaskryptu.sh > statusplik 2>&1 &

Możesz też wyjście przekierować do NULL, a wyjście błędów (komunikaty błędów) do pliku:

sh -c ./nazwaskryptu.sh > /dev/null 2> logibledow &

W ten sposób unikniesz dużych logów, a w pliku tylko będą znajdować się informacje o niepowodzeniach tylko rozłączenie itp.

Potem sobie sprawdzać, co się z wgetem dzieje:

cat statusplik | tail -n 5

Zainteresowała mnie ta opcja:

Niestety, chyba nie potrafię zastosować jej w praktyce

Obecnie mój skrypt, po spersonalizowaniu wygląda tak:

#!/bin/bash

DATA=`date +%d-%m-%Y_%H-%M`

NAZWAPLIKU=$DATA"-rw"

wget -c -nc --waitretry=1 --tries=0  http://stream4.nadaje.com:9240/prw -O /home/rostov/JW/$NAZWAPLIKU.mp3 -o /home/rostov/JW/log/$NAZWAPLIKU.log

done

A wpis w cronie tak:

15 11 * * 1,2,3,4,5,6,7 sh /home/rostov/rw.sh

Co więc powinienem zmodyfikować i w jaki sposób, by do logów były zapisywane tylko komunikaty o ewentualnych błędach? Wpis w skrypcie czy w cronie?

W CRONie musisz zmodyfikować wywołanie skryptu.
Dla kompletnego przekierowania wszystkich komunikatów do NULL oprócz błędów, które wędrują do pliku według tego, co napisałem będzie wyglądać tak:

15 11 * * 1,2,3,4,5,6,7 sh -c /home/rostov/rw.sh > /dev/null 2> /home/rostov/wget-errlog.log &

Sprawdzić, czy “wget” działa wywołany przez CRONa możesz sprawdzając, czy działa jego proces:

ps -A | grep wget

A logi sprawdzasz:

cat $HOME/wget-errlog.log | tail -n 5

(wyświetli coś jeżeli wget sypnie błędem)
(w skrócie tail -n 5 powoduje, że wyświetli Ci się 5 ostatnich linijek z pliku wget-errlog.log, a $HOME to zmienna środowiskowa i pod nią jest “/home/rostov” - możesz wpisać całą ścieżkę, ale moim zdaniem wygodniej jest wpisać $HOME -> w cron $HOME chyba Ci nie zadziała, więc tam tego nie używaj)

Z parametrem -c skrypt nie chciał się uruchomić. Dopiero usunięcie go spowodowało, że ustawione w cronie 5-minutowe nagrywanie (z zatrzymaniem skryptu przy użyciu skryptu kill.sh, którego kod prezentowałem powyżej) powiodło się. Jednak otrzymałem log błędów następującej treści:

/home/rostov/rw.sh: linia 7: 10950 Unicestwiony            wget -c -nc --waitretry=1 --tries=0 http://stream4.nadaje.com:9240/prw -O /home/rostov/JW/$NAZWAPLIKU.mp3 -o /home/rostov/JW/log/$NAZWAPLIKU.log
/home/rostov/rw.sh: linia 9: błąd składni przy nieoczekiwanym znaczniku `done'
/home/rostov/rw.sh: linia 9: `done'

Rozumiem więc, ze powinienem usunąć ze skryptu znacznik

done

oraz:

-o /home/rostov/JW/log/$NAZWAPLIKU.log

Skąd natomiast fraza ‘10950 Unicestwiony’ w odniesieniu do 7 linii skryptu? Czy tyczy się to zatrzymania skryptu skryptem kill.sh:

#!/bin/bash

killall -9 wget

??

“-c” nie jest niezbędne i możesz to pominąć. (oznacza “command”, czyli przekazanie parametrów do wykonania - często w SSH się używa, żeby przy każdej sesji z “ręki” nie wpisywać)

Unicestwiony odnosi się do zabicia procesu poleceniem “killall -9”, dlatego proponowałem “-3” zamiast “-9”, bo wtedy zwyczajnie proces nie jest zabity tylko wychodzi ze statusem “0”, czyli poprawnie zakończony i w logach błędu śladu nie ma w takim przypadku.
“done” usuń, bo to domknięcie pętli “while”, którą wcześniej wywaliłeś.
Resztę zostaw bez zmian - powinno działać.

Chyba coś nie tak. Dokonałem zmian następujących:

Skrypt rw.sh (nagrywanie pierwszej audycji):

#!/bin/bash

DATA=`date +%d-%m-%Y_%H-%M`

NAZWAPLIKU=$DATA"-rw"

wget -c -nc --waitretry=1 --tries=0  http://stream4.nadaje.com:9240/prw -O /home/rostov/JW/$NAZWAPLIKU.mp3

Skrypt rwk.sh (nagrywanie drugiej audycji):

#!/bin/bash

DATA=`date +%d-%m-%Y_%H-%M`

NAZWAPLIKU=$DATA"-rwk"

wget -c -nc --waitretry=1 --tries=0  http://stream4.nadaje.com:9230/rwkultura -O /home/rostov/JW/$NAZWAPLIKU.mp3

Skrypt kill.sh (zatrzymujący):

#!/bin/bash

killall -3 wget

Cron:

55 20 * * 1,2,3,4,5,6,7 sh /home/rostov/rwk.sh > /dev/null 2> /home/rostov/JW/error.log &
15 01 * * 1,2,3,4,5,6,7 sh /home/rostov/kill.sh
15 11 * * 1,2,3,4,5,6,7 sh /home/rostov/rw.sh > /dev/null 2> /home/rostov/JW/error.log &
35 11 * * 1,2,3,4,5,6,7 sh /home/rostov/kill.sh
* * * * * find ~/JW -mtime +7 -type f -delete
30 19 * * 1,2,3,4,5,6,7 sh /home/rostov/rw.sh > /dev/null 2> /home/rostov/JW/error.log &
35 19 * * 1,2,3,4,5,6,7 sh /home/rostov/kill.sh

Ostatnie dwie linijki ustawiłem na próbę. Powinien się nagrać 5-minutowy plik mp3, jak to się stało poprzednio. Zapomniało mi się trochę o tym i dopiero teraz zajrzałem na shella. I widzę, że nagrywanie ustawione na 19:30 (które powinno zakończyć się o 19:35) leci cały czas. Wygląda na to, że nie zadziałał skrypt kill.sh z -3 zamiast -9. W międzyczasie zaczęło się kolejne, zaplanowanie nagrywanie. Tym razem ze skryptu rwk.sh. Powstał plik error.log, do którego zaczęły trafiać nie tylko komunikaty o błędach. Spróbowałem zatrzymać działające akurat procesy poleceniem killall -3 wget, ale nie zatrzymało to nagrywania. Dopiero zadziałało z parametrem -9. O co chodzi?

Widocznie wget nie obsługuje przerwania poprzez SIG QUIT. Spróbuj jeszcze zamiast “-3"
”-s TERM" (TERM - z dużych liter)

A co do pliku error.log to wywal może z CRON “> /dev/null 2> …”, a dodaj bezpośrednio w pliku “rw.sh

Dało to tyle, że tym razem działanie skryptu zostało przerwane właściwie, natomiast powstały plik error.log zawiera wszystkie te informacje, co log utworzony poprzez dopisanie w skrypcie:

-o /home/rostov/JW/log/$NAZWAPLIKU.log

a nie tylko komunikaty błędów, których tym razem nie było.

Poszukałem w necie co jest nie tak z tym wget’em i okazuje się, że wszystkie komunikaty wysyła na standardowe wyjście błędów, ponieważ standard POSIX dopuszcza wysyłanie danych diagnostycznych na to wyjście.
Można nieco go uciszyć dodając po “wget” “-nv” - powoduje wypisanie tylko podstawowych danych w tym błędów. Dodając "| grep -i “błąd” dodatkowo filtrujemy po słowie kluczowym.

wget -nv -c -nc --waitretry=1 --tries=0 http://stream4.nadaje.com:9230/rwkultura -O /home/rostov/JW/$NAZWAPLIKU.mp3 > /dev/null 2> /home/rostov/JW/error.log | grep -i “błąd” &

Teraz to dopiero to wygląda :smiley:
Nic innego mi do głowy nie przychodzi. :stuck_out_tongue:

Zrobiłem trochę inaczej. W skryptach rw.sh i rwk.sh wróciłem do:

-o /home/rostov/JW/log/$NAZWAPLIKU.log

zachowując jednocześnie parametr -nv. W skrypcie kill.sh zachowałem z kolei:

killall -s TERM wget

W ten sposób otrzymuję osobny log dla każdego pliku nagrywania. Gdy nie ma błędów, jest on po prostu pusty. Zobaczymy, jaka będzie jego zawartość, gdy pojawią się znów jakieś błędy połączenia. :slight_smile: