Wiem, jak przekierować standardowe wyjście do pliku:
exec > foo.log
echo test
spowoduje to umieszczenie „testu” w pliku foo.log.
Teraz chcę przekierować dane wyjściowe do pliku dziennika i zachować je na standardowym wyjściu
tzn. można to zrobić trywialnie spoza skryptu:
script | tee foo.log
ale chcę to zadeklarować w samym skrypcie
próbowałem
exec | tee foo.log
ale to nie zadziałało.
Odpowiedzi:
Zauważ, że tak
bash
nie jestsh
. Jeśli wywołasz skrypt za pomocąsh myscript.sh
, pojawi się błąd wzdłuż liniisyntax error near unexpected token '>'
.Jeśli pracujesz z pułapkami sygnałowymi, możesz użyć
tee -i
opcji, aby uniknąć zakłóceń na wyjściu w przypadku wystąpienia sygnału. (Podziękowania dla JamesThomasMoon1979 za komentarz.)Narzędzia, które zmieniają dane wyjściowe w zależności od tego, czy zapisują na potoku, czy na terminalu (
ls
na przykład używając kolorów i skolonizowanych danych wyjściowych) wykryją powyższą konstrukcję jako oznaczającą, że wysyłają dane do rury.Istnieją opcje wymuszenia kolorowania / kolumnizacji (np
ls -C --color=always
.). Zauważ, że spowoduje to zapisanie kodów kolorów również w pliku dziennika, co czyni go mniej czytelnym.źródło
tee
nie powinien buforować danych wyjściowych. Jeśli buforuje w większości systemów, jest uszkodzony w większości systemów. To jest problemtee
implementacji, a nie mojego rozwiązania.exec
jest bardzo potężny, ale także bardzo zaangażowany. Możesz „wykonać kopię zapasową” bieżącego standardu do innego skryptu plików, a następnie odzyskać go później. Google „samouczek bash exec”, istnieje wiele zaawansowanych rzeczy.exec
jest udokumentowane , aby nie rozpocząć nowe procesy,>(tee ...)
to standard nazwany podstawienie rura / procesu, a&
w przekierowania oczywiście nie ma nic wspólnego ze w tło ... :-)?-i
dotee
. W przeciwnym razie przerwanie sygnału (pułapki) zakłóci standardowe wyjście w głównym skrypcie. Na przykład, jeśli masztrap 'echo foo' EXIT
a następnie naciśnijctrl+c
, nie zobaczysz „ foo ”. Więc zmodyfikowałbym odpowiedź naexec &> >(tee -ia file)
.Akceptowana odpowiedź nie zachowuje STDERR jako osobnego deskryptora pliku. To znaczy
nie będzie wyświetlać
bar
danych wyjściowych w terminalu, tylko w pliku dziennika iwypisze zarówno
foo
ibar
do terminala. Najwyraźniej takiego zachowania się nie spodziewa zwykły użytkownik. Można to naprawić za pomocą dwóch oddzielnych procesów tee dołączonych do tego samego pliku dziennika:(Zauważ, że powyższe nie początkowo obcina plik dziennika - jeśli chcesz tego zachowania, powinieneś dodać
na początek skryptu).
Specyfikacja POSIX.1-2008
tee(1)
wymaga, aby dane wyjściowe nie były buforowane, tzn. Nie są nawet buforowane w linii, więc w tym przypadku możliwe jest, że STDOUT i STDERR mogą znaleźć się w tym samym wierszufoo.log
; może się to jednak zdarzyć na terminalu, więc plik dziennika będzie wiernym odzwierciedleniem tego, co można zobaczyć na terminalu, jeśli nie będzie jego dokładnym odzwierciedleniem. Jeśli chcesz, aby wiersze STDOUT były wyraźnie oddzielone od wierszy STDERR, rozważ użycie dwóch plików dziennika, być może z prefiksem datownika w każdym wierszu, aby umożliwić późniejsze ponowne składanie chronologiczne.źródło
exec > >(tee -a $LOG)
trap "kill -9 $! 2>/dev/null" EXIT
exec 2> >(tee -a $LOG >&2)
trap "kill -9 $! 2>/dev/null" EXIT
-i
dotee
. W przeciwnym razie przerwanie sygnału (pułapki) zakłóci standardowe wyjście w skrypcie. Na przykład, jeśli naciśniesz,trap 'echo foo' EXIT
a następniectrl+c
nie zobaczysz „ foo ”. Więc zmodyfikowałbym odpowiedź naexec > >(tee -ia foo.log)
.. log
lub. log foo.log
: sam.nipl.net/sh/log sam.nipl.net/sh/log-aSTDOUT
pojawią się najpierw jako partia, a następnie wiadomościSTDERR
. Nie są przeplatane, jak zwykle się spodziewano.Rozwiązanie dla powłok busy busy, macOS bash i non-bash
Przyjęta odpowiedź jest z pewnością najlepszym wyborem na bash. Pracuję w środowisku Busybox bez dostępu do bash i nie rozumie
exec > >(tee log.txt)
składni. To też nie działaexec >$PIPE
poprawnie, próbując utworzyć zwykły plik o tej samej nazwie co nazwany potok, który nie działa i zawiesza się.Mam nadzieję, że przydałoby się to komuś, kto nie ma bashu.
Również dla każdego używającego nazwanego potoku jest to bezpieczne
rm $PIPE
, ponieważ powoduje to odłączenie potoku od VFS, ale procesy, które go używają, nadal utrzymują licznik referencyjny, dopóki nie zostaną zakończone.Uwaga: użycie $ * niekoniecznie jest bezpieczne.
źródło
W pliku skryptu umieść wszystkie polecenia w nawiasach:
źródło
{}
)Łatwy sposób na utworzenie dziennika skryptu bash do syslog. Dane wyjściowe skryptu są dostępne zarówno przez, jak
/var/log/syslog
i przez stderr. syslog doda przydatne metadane, w tym znaczniki czasu.Dodaj tę linię u góry:
Ewentualnie wyślij dziennik do osobnego pliku:
Wymaga to
moreutils
(dlats
polecenia, które dodaje znaczniki czasu).źródło
Korzystając z zaakceptowanej odpowiedzi, mój skrypt wracał wyjątkowo wcześnie (zaraz po „exec>> (tee ...)”), pozostawiając resztę skryptu działającą w tle. Ponieważ nie mogłem zmusić tego rozwiązania do działania, znalazłem inne rozwiązanie / obejście problemu:
Powoduje to, że dane wyjściowe skryptu przechodzą z procesu, przez potok do procesu podrzędnego procesu „tee”, który rejestruje wszystko na dysku i do oryginalnego standardowego skryptu.
Zauważ, że „exec &>” przekierowuje zarówno stdout, jak i stderr, możemy je przekierować osobno, jeśli chcemy, lub zmienić na „exec>”, jeśli chcemy tylko stdout.
Nawet jeśli potok zostanie usunięty z systemu plików na początku skryptu, będzie działał do momentu zakończenia procesów. Po prostu nie możemy odwoływać się do niego przy użyciu nazwy pliku po linii rm.
źródło
$logfile
częścitee < ${logfile}.pipe $logfile &
. W szczególności próbowałem to zmienić, aby przechwycić pełne rozwinięte wiersze dziennika poleceń (zset -x
) do pliku, pokazując tylko wiersze bez wiodącego „+” na standardowym wyjściu, zmieniając na,(tee | grep -v '^+.*$') < ${logfile}.pipe $logfile &
ale otrzymałem komunikat o błędzie dotyczący$logfile
. Czy możesz wyjaśnićtee
linię nieco bardziej szczegółowo?Bash 4 ma
coproc
polecenie, które ustanawia nazwany potok do polecenia i umożliwia komunikację za jego pośrednictwem.źródło
Nie mogę powiedzieć, że czuję się swobodnie z jakimkolwiek rozwiązaniem opartym na exec. Wolę używać tee bezpośrednio, więc na żądanie wykonuję skrypt w tee:
To pozwala ci to zrobić:
Możesz to dostosować, np. Ustaw tee = false jako wartość domyślną, zamiast tego TEE zatrzyma plik dziennika, itd. Myślę, że to rozwiązanie jest podobne do rozwiązania jbarlow, ale prościej, może moje ograniczenia, z którymi jeszcze się nie spotkałem.
źródło
Żadne z nich nie jest idealnym rozwiązaniem, ale oto kilka rzeczy, które możesz wypróbować:
lub
Drugi zostawiłby plik potoku na siedzeniu, jeśli coś pójdzie nie tak ze skryptem, co może, ale nie musi stanowić problemu (tj. Może
rm
później możesz to zrobić w powłoce nadrzędnej).źródło
tee
- edytowałem. Jak powiedziałem, żadne z nich nie jest idealnym rozwiązaniem, ale procesy w tle zostaną zabite, gdy ich macierzysta powłoka zakończy działanie, więc nie musisz się martwić, że na zawsze zablokują zasoby.