Jak wyciąć część z pliku dziennika?

18

Mam plik dziennika 8 Gb (dziennik produkcji Railsów). Muszę go wyciąć między niektórymi datami (liniami). Jakiego polecenia mogę tego użyć?

Eric Leschinski
źródło
1
Cześć chłopaki, to pytanie dotyczy dużego pliku, więc brzmi „Ante up!” ... liczy się czas ... Testowałem ulubiony skrypt sed na prawdziwym pliku 8 GB, z 85904064 liniami (100 znaków w linii). Uwielbiam sed, ale na obecnym etapie skrypt sed skanuje cały plik za każdym razem. To sprawia, że ​​jest średnio dwa razy wolniejszy niż skrypt awk, który kończy działanie po znalezieniu ... Myślę, że (?) Skrypt sed może potrzebować po prostu aq zamiast d dla drugiego wyrażenia ... Wyniki testu są tutaj: wklej .ubuntu.com / 573477 .. Poza tym nie generuje poprawnego wyniku .. patrz mój komentarz na końcu odpowiedzi asoundmove.
Peter.O
nowa wersja sed asoundmove rozwiązała problem prędkości i teraz pasuje do prędkości awks. a nowy versin teraz poprawnie wyświetla dane ... zobacz jego komentarze, aby uzyskać więcej szczegółów.
Peter.O
Właśnie zauważyłem, że powiedziałeś „wyciąć” (co zwykle oznacza usunięcie)… Czy naprawdę masz na myśli „wyciąć”, czy masz na myśli „kopiowanie”? .... Jeśli miałeś na myśli „cut”, to sedzrobisz to łatwo.
Peter.O

Odpowiedzi:

12

Coś jak

sed '1,/last date prior to chunk/d;/first date after chunk/,$d' logfile | tee cut-log | less

tee cut-logpozwala zobaczyć na ekranie, co jest wstawiane do pliku cut-log.

EDYTOWAĆ:

Aby spełnić rygorystyczne standardy fred.bear, oto rozwiązanie sed (choć prawdopodobnie awk jest o wiele ładniejsze):

b=BB; e=EE ;echo -e "AA\nAA\nBB\nBB\nCC\nCC\nDD\nDD\nEE\nEE\nFF\nFF" | sed -n ":b;/$b/b p;n;b b;:p;p;n;/$e/b e;b p;:e;p;n;/$e/b e;q"
asoundmove
źródło
3
@dogbane: tak, tak. Edytowane. Jestem pewien, że czasami piszesz mniej niż optymalny kod, czy zasługuje na tak ostry komentarz?
asoundmove
1
Uwaga: Jeśli istnieje wiele kolejnych wierszy „pierwsza data” z tą samą datą, wszystkie oprócz pierwszej nie zostaną usunięte i zostaną wprowadzone do wyniku ... po prostu coś, o czym należy pamiętać ... (zależy to od sytuacja)
Peter.O,
1
... ale mimo tego, że jestem pro-sed ++, myślę, że ta konkretna praca wykracza poza jej granice, w odniesieniu do czegoś innego niż własne narzędzie osobiste. Oto główny problem sed w tym przypadku (twoje i mój .. Udało mi się nakłonić seda do zrobienia tego samego co twój .. również działało w granicach 1%) .. powrót do głównego problemu .. (który nie dotyczy awk) .... Błąd (nie do naprawienia): Jeśli chodzi o datę, która jest ważna w zakresie dziennika, ale faktycznie go nie ma w dzienniku, w przypadku pierwszego argumentu spowoduje, że sed nic nie wydrukuje, a w przypadku drugiego argumentu sed wydrukuje wszystko po pierwszej randce! ... więcej ...
Peter.O
1
Kolejny, możliwy do naprawienia błąd: polega na tym, że obecnie pasuje do dat w dowolnym wierszu, w tym do ochrony danych, ale to tylko modyfikacja wyrażeń regularnych .. I dla każdego, kto chce go użyć, być może mógłbyś skomentować, że argumenty odnoszą się teraz do pierwszego i ostatnie daty w przedziale (nie -1 i +1) .. i wreszcie ... moje „wymagające standardy” nie są moje. Jestem tylko posłańcem wniosek pytających ... Użytkownik będzie zauważyć, czy działa zgodnie z wnioskiem, czy też nie .. To była wielka sprawa dla mnie .. Nauczyłem się dużo :) ... a ja zadowolony aby wiedzieć, że to sedmoże się równać awkz prędkością, a tak naprawdę było trochę szybciej.
Peter.O
6

Aby wydrukować wszystko między FOO i BAR włącznie, spróbuj:

$ sed -n '/FOO/,/BAR/p' file.txt
dogbane
źródło
1
Uwaga: Spowoduje to wydrukowanie tylko pierwszej BAR z serii kolejnych BARS ...
Peter.O
inna uwaga ... Duży problem, jeśli którakolwiek z dat nie jest obecna w danych .. Jeśli ostatnia data nie jest obecna, sed będzie wyświetlał wiersze, aż dotrze do EOF.
Peter.O
5

To zrobi, co chcesz ... Wyświetlane są
zarówno Dołączanie, jak i Wyłączanie dat parametrów.

# set Test args
set  2011-02-24  2011-02-26  "junk"

from="$1"
till="$2"
file="$3"

# EITHER ====                              +++++++++  
# Ouptut lines between two parameter dates INCLUDING the parameter dates
  awk -v from=$from -v till=$till '
    ($2 >= from) && ($2 <= till) { print $0 ; next }
    ($2 > till) { exit }' "$file"

# OR ========                              ---------
# Ouptut lines between two parameter dates EXCLUDING the parameter dates
  awk -v from=$from -v till=$till '
    ($2 > from) && ($2 < till) { print $0 ; next }
    ($2 >= till) { exit }' "$file"

Testuje na (posortowaną) datę w polu 2 ... Oto przykład danych testowych

    98  2011-02-05 xxxx
    99  2011-02-05 xxxx
   100  2011-02-06 xxxx
   101  2011-02-06 xxxx

A oto generator danych testowych .

Peter.O
źródło
Chciałbym napisać to (biorąc na przykład pierwszy) nieco prościej w ten sposób: awk -v from="$from" -v till="$till" '($2 >= from) { if ($2 <= till) { print } else { exit }' "$file"
asoundmove
@asoundmove: Tak, to może wyglądać lepiej i jest zdecydowanie bardziej konwencjonalne , ale w rzeczywistości czas jego wykonania to tylko czas trwania 1 dodatkowej ifinstrukcji w sumie (nawet 1 na linię), tj. przepływ logiczny jest faktycznie taki sam, a różnica w czasie wykonywania będzie liczona w nanosekundach. Jedynym powodem, dla którego nie użyłem „innego” jest to, że jest to faktycznie mój pierwszy w historii awkskrypt (oprócz jednego dnia 4 lat temu, kiedy grałem z kilkoma przykładami) ... i to jest pierwszy działający mechanizm gałęzi, który znalazłem ... (i jak wspomniano. jest tak samo szybki) .. Generalnie używam sedTryq
Peter.O
Nie rozumiem, gdzie podajesz nazwę i lokalizację pliku tekstowego w tej metodzie? czy ktoś może mi pomóc przejrzeć moją głupotę
Giles
4

Jeśli w pliku dziennika masz daty w tym formacie YYYY-MM-DD, to aby znaleźć wszystkie wpisy, powiedzmy, 2011-02-10, możesz:

grep 2011-02-10 log_file

Powiedzmy teraz, że jeśli chcesz znaleźć wpisy dla 2011-02-10 i 2011-02-11, ponownie użyj, grepale z wieloma wzorami:

grep -E '2011-02-10|2011-02-11' log_file
Barun
źródło
Dobry. Działa „jak w reklamie” :) ... grepPrzeszukuje jednak cały plik, nawet jeśli zakres dat znajduje się na początku pliku. Średnio podwaja to czas wyszukiwania w porównaniu z „wyjściem z ostatniego elementu w zakresie” ... Niepokoi mnie to tylko z powodu rozmiaru pliku 8 GB, o którym mowa w pytaniu wyniki czasu grep są prawie identyczne jak w przypadku sed tutaj (1min 58s). Oto link do moich wyników testów czasowych: paste.ubuntu.com/573477
Peter.O
1

Praca z plikami tego rozmiaru jest zawsze trudna.

Rozwiązaniem może być podzielenie tego pliku na kilka małych. Aby to zrobić, możesz użyć polecenia split.

split -d -l 50000 ToBigFile.data file_

Nawet jeśli jest on podzielony, nadal możesz pracować z plikiem tak, jakbyś używał basha dla pętli

for f in `ls file_*`; do cat $f; done;

Ale zamiast kota możesz użyć odwróconego grepa, aby pozbyć się niechcianych danych, co nie ma w tym przypadku znaczenia. (lub rodzaj udoskonalenia, którego potrzebujesz).

W tym momencie będziesz po prostu pracować z wieloma mniejszymi plikami, a polecenia, o których wspomniano powyżej, będą działały duszniej na wielu mniejszych plikach.

A kiedy skończysz, możesz użyć drugiej pętli for, aby ponownie zbudować nowy, mniejszy plik.

for f in `ls file_*`; do cat $f >> NewFile.data ; done;

Aktualizacja Ponieważ zaczynamy dzielić dane na wiele plików, będzie dużo pracy z dyskiem twardym, co zajmuje dużo czasu. (W tym pytaniu najwyraźniej 5 minut).

Z drugiej strony kolejne kroki byłyby prawdopodobnie szybsze.

Ta metoda jest więc prawdopodobnie bezcelowa dla prostej operacji grep, awk, sed, ale jeśli wzorce wyszukiwania stają się bardziej skomplikowane, może stać się szybsze.

Johan
źródło
3
Johanm, przeszukanie pliku dziennika o wielkości 8 GB na moim komputerze zajmuje średnio awk i sed tylko 1 minutę, a na tym samym komputerze, tylko początkowe dzielenie plików, zajmuje 4 minuty 43 sekundy ... :)
Peter.O
Powiedzmy, że możesz zmniejszyć te czasy awk i sed o 50% na mniejszych plikach. Następnie musimy wykonać więcej niż 10 z tych operacji, zanim zyskamy na łącznym czasie ... Może więc podział plików nie jest najlepszym pomysłem na kilka regresji ...
Johan
Skrypt awk można (łatwo) zmodyfikować, aby wyświetlał 10 różnych wyników wyszukiwania w 10 plikach .. w jednym przejściu, ale to spowolniłoby odczyt podczas faktycznego generowania raportów ... Sed może również zrobić to samo, ale tak jak ja wspomniano w komentarzach asoundmove, sed nie powiedzie się, jeśli dana data / godzina nie ma wpisu w dzienniku (np. szukasz godziny) .. Używam sed dużo i jest to bardzo przydatne, ale ma swoje ograniczenia ... Oto najczęściej zadawane pytania dotyczące sed, kiedy używać sed vs awk. Niekoniecznie zgadzam się z tym wszystkim, ale rozumiem, co one oznaczają ... sed.sourceforge.net/sedfaq6.html
Peter. O
0
perl -wlne '/^2011-02-24/ .. /^2011-02-25/ and print' log_file
charlesbridge
źródło
Spowoduje to jednak wydrukowanie tylko pierwszego wpisu dziennika dla 02.02.2011.
Gilles „SO- przestań być zły”,