[bash] zatrzymywanie nagrywania wget

Nagrywam przy pomocy shella audycje z dwóch różnych strumieni. Robię to przy użyciu następujących skryptów, które uruchamiają o wybranych godzinach odpowiednie wpisy w cronie:

#!/bin/bash

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

NAZWAPLIKU=$DATA

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

oraz

#!/bin/bash

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

NAZWAPLIKU=$DATA

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

Nagrywanie zatrzymuję uruchamianym przez cron o odpowiednich porach skryptem:

#!/bin/bash

killall -s TERM wget 

Mam jednak pewien problem, gdy pokrywają się czasy nagrywania obu audycji. Wówczas muszę kończyć nagranie audycji krótszej w momencie końca audycji dłuższej, by nie obciąć tej drugiej.
W jaki sposób, używając skryptu kill, kończyć działanie poszczególnych skryptów, a nie wszystkich?

Nieco trzeba zmodyfikować, aby uwalać wget po PIDzie.

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 2>&1 & PID1=`echo $!`

wget -c -nc --waitretry=1 --tries=0 http://stream4.nadaje.com:9230/rwkultura -O /home/rostov/JW/$NAZWAPLIKU.mp3 -o /home/rostov/JW/log/$NAZWAPLIKU.log 2>&1 & PID2=`echo $!`

"QUIT":
DLA pierwszego WGET:
kill $PID1

DLA drugiego WGET:
kill $PID2

Słowem wyjaśnienia:
2>&1 (przekierowuje standardowe wyjście błędów na standardowe wyjście)
& (przenosi proces w tryb “tła” / background)
PID1=`echo $!` (podstawia pod zmienną PID1 numer PID procesu wget aktualnie uruchomionego w tle)

kill $PID1 (TERM (terminate))
kill $PID2 (analogicznie do w. w.)

Oczywiście nie stoi nic na przeszkodzie, żeby w każdej chwili sprawdzić procesy zadań wget w tle.
W konsoli wpisujesz w takim wypadku jobs pokazuje Ci zadania w tle, potem
fg NUMER_ZADANIA , żeby “wydobyć na wierzch” jak chcesz przerwać zadanie to po wydobyciu Ctrl+C
jeżeli z powrotem wysłać w tło to Ctrl+Z, a następnie: bg NUMER_ZADANIA
i wtedy działa sobie dalej w tle.
jobs również wypisuje Ci PIDy zadań w tle więc możesz użyć kill %NUMER_ZADANIA i to będzie równoznacznie z jego zakończeniem.
:wink:

A trzy ``` z enterami je rozdzielającymi od kodu też źle się zachowują?

1 polubienie

Fakt - zapomniałem o tym formatowaniu.
Zrobiłem tak:
```bash
KOD
```
Całkiem wygodne dla bloku tekstu :slight_smile:
https://support.codebasehq.com/articles/tips-tricks/syntax-highlighting-in-markdown

Czyli rozumiem, że dla każdego skryptu nagrywania wget musi być oddzielny skrypt killujący?
Czy może wystarczy taki wpis w cronie:

50 20 * * 1,2,3,4,5,6,7 kill $PID1

Wybaczcie lamerstwo pytania, ale cała moja wiedza nt. basha ogranicza się do tych prostych skryptów.

Rosov

Tak dla formalności zapytam, znasz program streamripper? Parametr małe L to liczba sekund, po której nagrywanie ma zostać zatrzymane.

Poszukaj info pod hasłem “bash script timeout”:
http://fahdshariff.blogspot.com/2013/08/executing-shell-command-with-timeout.html .

Znam, ale rzadko mogę sobie pozwolić na pozostawienie włączonego komputera w czasie nagrywania audycji. Dlatego używam do tego celu shella.

Najprościej, nazwij oba skrypty inaczej i ubijaj po nazwie skryptu.

#!/bin/bash

NAZWAPLIKU=$(date +%F_%H_%M)

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

Chyba się gubię. Powinienem to robić w dwóch osobnych skryptach killujących dla każdego ze skryptów nagrywających, czy w osobnych wpisach do crontaba?

To, co ja podałem to w osobnych wpisach w crontabie, ponieważ parametr “$!” nie może być przekazywany “na zewnątrz”.
Czyli:
CRONTAB:

start pierwszego wget
start drugiego wget

start kill dla pierwszego wget
start kill dla drugiego wget

W cron wywolujesz 2 zadania. Czy skrypt napiszesz jeden czy dwa, to już zależy od Ciebie. Możesz zrobić tak jak napisal domker lub napisać 2 osobne skrypty i killowac je po ich nazwie.

Gdy uruchomisz skypt1.sh i sprawdzisz sobie procesy poleceniem ps, to zobaczy uruchomiony skrypt w procesach i jego nazwę.

Jeśli skrypt nagrywający uruchamiasz o konretnej godzinie i o konretnej go ubijasz oraz uruchamiasz jeden po drugim, to masz jeszcze prostsze rozwiązanie.

0 20 * * * bash skrypt_nagrywajacy.sh
50 20 * * * killall wget && bash skrypt_nagrywajacy.sh
0 22 * * * killall wget

lub

0 20 * * * bash skrypt_nagrywajacy.sh
50 20 * * * killall skrypt_nagrywajacy.sh && bash skrypt_nagrywajacy.sh
0 22 * * * killall skrypt_nagrywajacy.sh

zawsze można zainteresować się poleceniem pkill
https://linux.die.net/man/1/pkill

Wrzuciłem do crontaba 2 takie wpisy testowe:

25 19 * * 7 bash rw.sh
26 19 * * 7 killall rw.sh

rw.sh - mój skrypt nagrywający.
Kiedy o 19:30 zalogowałem się przez ftp do katalogu, do którego powinna trafiać nagrywana audycja, zauważyłem, że nagrywa się dalej. Co ciekawe — polecenie ps wcale nie wykazało, że uruchomiony jest ten skrypt, tylko 2 procesy: bash i ps. Jednak uruchomienie mojego starego skryptu killującego zatrzymało nagrywanie, więc skrypt uruchomiony był. Dlaczego killall nie zatrzymuje skryptu nagrywania i dlaczego w ogóle nie widać go w procesach?

Podpowie ktoś?

Musisz wydać polecenie: ps -A, jeżeli chcesz zobaczyć wszystkie procesy z poziomu konsoli.

Zabijając skrypt powstrzymujesz niejako go przed wykonaniem kolejnych “kroków”.
Jeżeli z poziomu skryptu odpalony jest jakiś program np. wget to zabijesz skrypt, a program zostanie w procesach dalej uruchomiony.

Przykład:

#!/bin/bash

echo "pierwszy krok ->sleep"
sleep 120
echo "dalszy krok"

Zapisz jako kill-test.sh, nadaj prawa uruchomieniowe, a następnie odpal w tle:
./kill-test.sh &

Potem Ctrl+C i spróbuj ubić:
killall kill-test.sh

Skrypt oczywiście ubijesz i nie wykona się nic po kroku “sleep 120” po upłynięciu czasu 120 sekund, a w procesach dalej będziesz widział działający proces “sleep”, który ukończy swoją pracę po 120 sek., ale reszta skryptu się nie wykona.

@Domker
Zastosowałem Twoje rozwiązanie z ubijaniem procesu po PID. Skopiowałem linijki, które podałeś i wkleiłem do crontaba. Start ustawiłem na 19:00, kill na 19:05. Kiedy zajrzałem o 19:15, nagrywanie leciało dalej. Ponadto nagrywał się plik bez nazwy, samo rozszerzenie .mp3

A no nie działa to Cron widzę, że otwiera nowe sesje dla każdego zadania z osobna i zmienne się nie przenoszą. Nazwa pliku Ci się nie zrobiła, bo pewnie źle użyłeś w jednej linijce generowania nazwy.

Poprawiona wersja:

NAZWAPLIKU=$(date +%d-%m-%Y_%H-%M) && 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 2>&1 & echo $! > /home/rostov/JW/log/PID1.tmp

NAZWAPLIKU=$(date +%d-%m-%Y_%H-%M) && wget -c -nc --waitretry=1 --tries=0 http://stream4.nadaje.com:9230/rwkultura -O /home/rostov/JW/$NAZWAPLIKU.mp3 -o /home/rostov/JW/log/$NAZWAPLIKU.log 2>&1 & echo $! > /home/rostov/JW/log/PID2.tmp


DLA pierwszego WGET:
kill $(cat /home/rostov/JW/log/PID1.tmp)

DLA drugiego WGET:
kill $(cat /home/rostov/JW/log/PID2.tmp)

Tym razem PIDy odczytuje z plików :wink:

@Domker
Zrobiłem 2 takie wpisy w crontabie:

05 10 * * 2 NAZWAPLIKU=$(date +%d-%m-%Y_%H-%M) && 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 2>&1 & echo $! > /home/rostov/JW/log/PID1.tmp
10 10 * * 2 kill $(cat /home/rostov/JW/log/PID1.tmp)

Niestety, tym razem nie nagrało się nic.

Kurcze pieczone ten cron to upierdliwy jest.
Trzeba zmienić generowanie nazwy na:

NAZWAPLIKU=`date +\%d-\%m-\%Y_\%H-\%M`

Okazuje się, że w przypadku daty wszystkie parametry trzeba poprzedzić eskejpem “\”, bo inaczej w tym momencie jest błąd i polecenie dalej się nie wykonuje ze względu na “&&”.
W crontab “%” ma widocznie jakąś jeszcze rolę.

1 polubienie