Chcę wstawić znacznik czasu do każdego wiersza wyniku polecenia. Na przykład:
foo
bar
baz
stanie się
[2011-12-13 12:20:38] foo
[2011-12-13 12:21:32] bar
[2011-12-13 12:22:20] baz
... gdzie prefiks to czas, w którym linia została wydrukowana. Jak mogę to osiągnąć?
Odpowiedzi:
moreutils obejmuje,
ts
co robi to całkiem ładnie:command | ts '[%Y-%m-%d %H:%M:%S]'
Eliminuje to również potrzebę pętli, każda linia wyjścia będzie miała na sobie znacznik czasu.
Chcesz wiedzieć, kiedy ten serwer wrócił, zrestartowałeś się? Po prostu uruchom
ping | ts
, problem rozwiązany: D.źródło
tail -f /tmp/script.results.txt | ts
ssh -v 127.0.0.1 2>&1 | ts
-s
jest przydatne. Jak to wyświetla środowisko uruchomieniowe polecenia. Ja osobiście lubię używać zarównots
its -s
w tym samym czasie. Wygląda tak:command | ts -s '(%H:%M:%.S)]' | ts '[%Y-%m-%d %H:%M:%S'
. To poprzedza następujące wiersze dziennika:[2018-12-04 08:31:00 (00:26:28.267126)] Hai <3
Po pierwsze, jeśli oczekujesz, że te znaczniki czasu będą faktycznie reprezentować zdarzenie, pamiętaj, że ponieważ wiele programów wykonuje buforowanie linii (niektóre bardziej agresywnie niż inne), ważne jest, aby myśleć o tym tak blisko czasu, jaki miałby oryginalny wiersz został wydrukowany, a nie znacznik czasu akcji.
Możesz także sprawdzić, czy twoje polecenie nie ma jeszcze wbudowanej funkcji dedykowanej do tego. Na przykład
ping -D
istnieje w niektórychping
wersjach i wypisuje czas od epoki Uniksa przed każdą linią. Jeśli twoje polecenie nie zawiera własnej metody, istnieje kilka metod i narzędzi, które można zastosować, między innymi:Powłoka POSIX
Pamiętaj, że ponieważ wiele powłok wewnętrznie zapisuje swoje łańcuchy jako łańcuchy, jeśli dane wejściowe zawierają znak null (
\0
), może to spowodować przedwczesne zakończenie linii.GNU awk
Perl
Pyton
Rubin
źródło
stdbuf -o 0
, ale jeśli program ręcznie obsługuje buforowanie wyjściowe, nie pomoże (chyba że istnieje opcja wyłączenia / zmniejszenia wielkości bufora wyjściowego).python -u
... for x in sys.stdin
iteruje po liniach bez buforowania ich wszystkich najpierw w pamięci.Do pomiaru delta linia po linii spróbuj gnomon .
źródło
ts
korzystania z procesów na żywo. Chociażts
lepiej nadaje się do procesów nieinteraktywnych.Post Ryana zawiera ciekawy pomysł, jednak pod wieloma względami zawodzi. Podczas testowania
tail -f /var/log/syslog | xargs -L 1 echo $(date +'[%Y-%m-%d %H:%M:%S]') $1
zauważyłem, że znacznik czasu pozostaje taki sam, nawet jeślistdout
później, z różnicami w sekundach. Rozważ to wyjście:Moje proponowane rozwiązanie jest podobne, jednak zapewnia odpowiednie oznaczanie czasu i wykorzystuje nieco bardziej przenośne
printf
niżecho
Dlaczego
bash -c '...' bash
? Ponieważ z powodu-c
opcji pierwszy argument zostaje przypisany$0
i nie pojawia się w danych wyjściowych. Zapoznaj się ze stroną podręcznika powłoki, aby uzyskać właściwy opis-c
Testowanie to rozwiązanie
tail -f /var/log/syslog
i (jak zapewne mógł odgadnąć) odłączeniu i ponownym podłączeniu do mojego wifi, wykazała właściwy czas tłoczenia zapewnia zarównodate
isyslog
komunikatyBash można zastąpić dowolną powłoką podobną do bourne, można to zrobić za pomocą jednego
ksh
lubdash
przynajmniej tych, które mają taką-c
opcję.Potencjalne problemy:
Rozwiązanie wymaga posiadania
xargs
, który jest dostępny w systemach zgodnych z POSIX, więc większość systemów uniksowych powinna zostać objęta. Oczywiście nie będzie działać, jeśli twój system nie jest zgodny z POSIX lub go nie maGNU findutils
źródło
Wolałbym komentować powyżej, ale nie mogę, reputacyjnie. W każdym razie powyższą próbkę Perla można niebuforować w następujący sposób:
Pierwsze „$ |” rozpakowuje STDOUT. Drugi ustawia stderr jako bieżący domyślny kanał wyjściowy i odznacza go. Ponieważ select zwraca oryginalne ustawienie $ |, owijając select wewnątrz select, resetujemy również $ | do wartości domyślnej STDOUT.
I tak, możesz wycinać i wklejać jak jest. Wielowarstwowo podłożyłem go dla czytelności.
A jeśli naprawdę chcesz uzyskać dokładność (i masz zainstalowany Time :: Hires ):
źródło
Większość odpowiedzi sugeruje użycie
date
, ale jest wystarczająco powolna. Jeśli twoja wersja bash jest większa niż 4.2.0, lepiej użyćprintf
zamiast tego, jest to wbudowana bash. Jeśli potrzebujesz obsługi starszych wersji bash, możesz utworzyćlog
funkcję zależną od wersji bash:Zobacz różnice prędkości:
UPD: zamiast
$(date +"${TIMESTAMP_FORMAT}")
tego lepiej jest użyć$(exec date +"${TIMESTAMP_FORMAT}")
lub nawet$(exec -c date +"${TIMESTAMP_FORMAT}")
przyspieszyć wykonanie.źródło
Możesz to zrobić za pomocą
date
ixargs
:Wyjaśnienie:
xargs -L 1
mówi xargsowi, aby uruchomił polecenie kontynuujące dla każdego 1 wiersza danych wejściowych, i przekazuje to w pierwszym wierszu.echo `date +'[%Y-%m-%d %H:%M:%S]'` $1
w zasadzie powtarza datę z argumentem wejściowym na końcuźródło
$1
. To nie jest dobry styl. Zawsze podawaj zmienne. Ponadto korzystaszecho
, co nie jest przenośne. Jest w porządku, ale może nie działać poprawnie w niektórych systemach.date
ponownej oceny każdej linii, czy jest to raczej beznadziejne?