Mam mały skrypt, który jest wywoływany codziennie przez crontab za pomocą następującego polecenia:
/homedir/MyScript &> some_log.log
Problem z tą metodą polega na tym, że plik some_log.log jest tworzony dopiero po zakończeniu działania MyScript. Chciałbym wrzucić dane wyjściowe programu do pliku podczas jego działania, aby móc na przykład robić rzeczy
tail -f some_log.log
i śledź postępy itp.
sys.stdout.flush()
.Odpowiedzi:
Sam bash nigdy nie zapisze żadnych danych wyjściowych do pliku dziennika. Zamiast tego polecenia, które wywołuje jako część skryptu, będą indywidualnie zapisywać dane wyjściowe i opróżniać je, gdy tylko zechcą. Więc tak naprawdę twoje pytanie brzmi, jak zmusić polecenia w skrypcie bash do opróżnienia, a to zależy od tego, czym one są.
źródło
Tutaj znalazłem rozwiązanie tego problemu . Korzystając z przykładu OP, w zasadzie uruchamiasz
a następnie bufor jest opróżniany po każdym wierszu wyjścia. Często łączę to z
nohup
wykonywaniem długich zadań na zdalnym komputerze.W ten sposób Twój proces nie zostanie anulowany po wylogowaniu.
źródło
stdbuf
? Na podstawie tego komentarza wydaje się, że nie jest on dostępny w niektórych dystrybucjach. Czy mógłbyś wyjaśnić?stdbuf
jest częścią GNU coreutils, dokumentację można znaleźć na stronie gnu.orgexport -f my_function
a następniestdbuf -oL bash -c "my_function -args"
jeśli potrzebujesz uruchomić funkcję zamiast skryptuKlucz to -f. Cytat ze skryptu man:
-f, --flush Flush output after each write. This is nice for telecooperation: one person does 'mkfifo foo; script -f foo', and another can supervise real-time what is being done using 'cat foo'.
Uruchom w tle:
źródło
busybox
! (moja muszla później się zawiesza, ale nieważne)Możesz użyć
tee
do zapisu do pliku bez potrzeby opróżniania.źródło
Nie jest to funkcja programu
bash
, ponieważ wszystko, co robi powłoka, to otwiera dany plik, a następnie przekazuje deskryptor pliku jako standardowe wyjście skryptu. To, co musisz zrobić, to upewnić się, że dane wyjściowe skryptu są opróżniane częściej niż obecnie.Na przykład w Perlu można to osiągnąć ustawiając:
Więcej informacji na ten temat znajdziesz w perlvar .
źródło
Buforowanie danych wyjściowych zależy od sposobu
/homedir/MyScript
implementacji programu . Jeśli zauważysz, że dane wyjściowe są buforowane, musisz wymusić to w swojej implementacji. Na przykład użyj sys.stdout.flush (), jeśli jest to program w języku Python, lub fflush (stdout), jeśli jest to program w C.źródło
Czy to pomogłoby?
tail -f access.log | stdbuf -oL cut -d ' ' -f1 | uniq
Spowoduje to natychmiastowe wyświetlenie unikatowych wpisów z access.log za pomocą narzędzia stdbuf .
źródło
stdbuf
dostępne w Ubuntu, nie jestem pewien, skąd je mam.stdbuf
jest częściącoreutilus
(znajduje się zapt-file search /usr/bin/stdbuf
).Jak tylko dostrzeżone tutaj problemem jest to, że trzeba czekać, że programy, które biegną od skryptu zakończyć pracę.
Jeśli w swoim skrypcie uruchamiasz program w tle , możesz spróbować czegoś więcej.
Generalnie wywołanie
sync
przed wyjściem pozwala opróżnić bufory systemu plików i może trochę pomóc.Jeśli w skrypcie uruchamiasz niektóre programy w tle (
&
), możesz poczekać , aż zakończą się, zanim wyjdziesz ze skryptu. Aby dowiedzieć się, jak to działa, możesz zobaczyć poniżej#!/bin/bash #... some stuffs ... program_1 & # here you start a program 1 in background PID_PROGRAM_1=${!} # here you remember its PID #... some other stuffs ... program_2 & # here you start a program 2 in background wait ${!} # You wait it finish not really useful here #... some other stuffs ... daemon_1 & # We will not wait it will finish program_3 & # here you start a program 1 in background PID_PROGRAM_3=${!} # here you remember its PID #... last other stuffs ... sync wait $PID_PROGRAM_1 wait $PID_PROGRAM_3 # program 2 is just ended # ...
Ponieważ
wait
działa zarówno z zadaniami, jak izPID
liczbami, leniwym rozwiązaniem powinno być umieszczenie na końcu skryptufor job in `jobs -p` do wait $job done
Trudniejsza jest sytuacja, jeśli uruchamiasz coś, co uruchamia coś innego w tle, ponieważ musisz wyszukać i poczekać (jeśli tak jest) na koniec całego procesu potomnego : na przykład, jeśli uruchamiasz demona, prawdopodobnie tak nie jest czekać, kończy się :-).
Uwaga:
czekaj $ {!} oznacza „czekaj, aż zakończy się ostatni proces w tle”, gdzie
$!
jest PID ostatniego procesu w tle. Tak więc wstawieniewait ${!}
tuż poprogram_2 &
jest równoważne wykonaniu bezpośrednioprogram_2
bez wysyłania go w tle za pomocą&
Z pomocy
wait
:Syntax wait [n ...] Key n A process ID or a job specification
źródło
Dzięki
@user3258569
, skrypt to być może jedyna rzecz, która działabusybox
!Jednak po tym muszla zamarzała. Szukając przyczyny, znalazłem te duże czerwone ostrzeżenia „nie używaj w powłokach nieinteraktywnych” na stronie podręcznika skryptów :
Prawdziwe.
script -c "make_hay" -f /dev/null | grep "needle"
zamrażał dla mnie muszlę.Wbrew ostrzeżeniu myślałem, że
echo "make_hay" | script
przejdzie EOF, więc spróbowałemecho "make_hay; exit" | script -f /dev/null | grep 'needle'
i zadziałało!
Zwróć uwagę na ostrzeżenia na stronie podręcznika. To może nie działać dla Ciebie.
źródło
Alternatywą dla stdbuf jest to,
awk '{print} END {fflush()}'
że chciałbym mieć wbudowany bash, który to robi. Zwykle nie powinno to być konieczne, ale w starszych wersjach mogą występować błędy synchronizacji bash w deskryptorach plików.źródło
Nie wiem, czy to zadziała, ale co z dzwonieniem
sync
?źródło
sync
jest niskopoziomową operacją systemu plików i nie ma związku z buforowanym wyjściem na poziomie aplikacji.sync
w razie potrzeby zapisuje brudne bufory systemu plików do pamięci fizycznej. Jest to wewnętrzne dla systemu operacyjnego; aplikacje działające w systemie operacyjnym zawsze widzą spójny obraz systemu plików niezależnie od tego, czy bloki dysku zostały zapisane w fizycznej pamięci masowej. W pierwotnym pytaniu aplikacja (skrypt) prawdopodobnie buforuje dane wyjściowe w buforze wewnętrznym aplikacji, a system operacyjny nie będzie nawet wiedział (jeszcze), że dane wyjściowe są faktycznie przeznaczone do zapisania na standardowe wyjście. Zatem hipotetyczna operacja typu „synchronizacja” nie byłaby w stanie „sięgnąć” do skryptu i wyciągnąć danych.Miałem ten problem z procesem w tle w systemie Mac OS X przy użyciu rozszerzenia
StartupItems
. Oto jak to rozwiązuję:Jeśli sprawię
sudo ps aux
, zobaczę, żemytool
jest uruchomiony.Zauważyłem, że (z powodu buforowania), gdy Mac OS X wyłącza się,
mytool
nigdy nie przesyła danych wyjściowych dosed
polecenia. Jeśli jednak wykonamsudo killall mytool
,mytool
przekazuje dane wyjściowe dosed
polecenia. Dlatego dodałem dostop
sprawy,StartupItems
która jest wykonywana, gdy Mac OS X się wyłącza:start) if [ -x /sw/sbin/mytool ]; then # run the daemon ConsoleMessage "Starting mytool" (mytool | sed .... >> myfile.txt) & fi ;; stop) ConsoleMessage "Killing mytool" killall mytool ;;
źródło
czy ci się to podoba, czy nie, tak działa przekierowanie.
W twoim przypadku wyjście (co oznacza, że skrypt się zakończył) twojego skryptu zostało przekierowane do tego pliku.
To, co chcesz zrobić, to dodać te przekierowania w swoim skrypcie.
źródło