Mam plik dziennika 8 Gb (dziennik produkcji Railsów). Muszę go wyciąć między niektórymi datami (liniami). Jakiego polecenia mogę tego użyć?
sed
zrobisz to łatwo.
Mam plik dziennika 8 Gb (dziennik produkcji Railsów). Muszę go wyciąć między niektórymi datami (liniami). Jakiego polecenia mogę tego użyć?
sed
zrobisz to łatwo.
Odpowiedzi:
Coś jak
sed '1,/last date prior to chunk/d;/first date after chunk/,$d' logfile | tee cut-log | less
tee cut-log
pozwala 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"
sed
może się równać awk
z prędkością, a tak naprawdę było trochę szybciej.
Aby wydrukować wszystko między FOO i BAR włącznie, spróbuj:
$ sed -n '/FOO/,/BAR/p' file.txt
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 .
awk -v from="$from" -v till="$till" '($2 >= from) { if ($2 <= till) { print } else { exit }' "$file"
if
instrukcji 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 awk
skrypt (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 sed
Tryq
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, grep
ale z wieloma wzorami:
grep -E '2011-02-10|2011-02-11' log_file
grep
Przeszukuje 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
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.
perl -wlne '/^2011-02-24/ .. /^2011-02-25/ and print' log_file