Mam plik z wieloma wierszami, a każdy wiersz ma na początku znacznik czasu, na przykład
[Thread-3] (21/09/12 06:17:38:672) logged message from code.....
Dlatego często sprawdzam 2 rzeczy z tego pliku dziennika.
- Podano również kilka pierwszych wierszy, które mają warunki globalne i czas rozpoczęcia.
- Ostatnie kilka wierszy, które mają status wyjścia z kilkoma innymi informacjami.
Czy jest jakieś szybkie, wygodne, pojedyncze polecenie, które pozwala mi wyświetlić tylko kilka pierwszych wierszy pliku?
head and tail
działa dla Ciebie?N
sed(1)
ekspertem, ale istnieją sposoby na schowanie rzeczy do późniejszego użytku. Może warto się tam zajrzeć. OTOH, prawdopodobnie użyłbym skryptu Perla (lub cokolwiek), aby to zrobić, jeśli jest często używany, ponieważ jestem bardziej zaznajomiony z tym.Odpowiedzi:
Możesz użyć
sed
lub,awk
aby zrobić to za pomocą jednego polecenia. Jednak stracisz szybkość, ponieważsed
i takawk
będzie musiał przejść przez cały plik. Z punktu widzenia prędkości znacznie lepiej jest wykonać funkcję lub za każdym razem kombinacjętail
+head
. Ma to tę wadę, że nie działa, jeśli dane wejściowe są potokiem, jednak można użyć podstawienia proccess, na wypadek, gdyby powłoka je obsługiwała (patrz przykład poniżej).i po prostu uruchom go jako
aby kontynuować proces podstawiania (tylko powłoki bash, zsh, ksh jak powłoki):
ps. możesz nawet dodać znak,
grep
aby sprawdzić, czy istnieją twoje „warunki globalne”.źródło
-n 10
jest domyślne, nie?-n 10
nie jest tu konieczne.@ rush ma rację, mówiąc, że użycie głowy i ogona jest bardziej wydajne w przypadku dużych plików, ale w przypadku małych plików (<20 linii) niektóre linie mogą być wyprowadzane dwukrotnie.
byłby równie wydajny, ale nie miałby powyższego problemu.
źródło
{head; tail;} < file
działa w Zsh, ale nie działa w SH.{ head; tail;} < file
zawsze działa. Przepraszam za hałas.head
powłoką, a nie z powłoką. POSIX wymagahead
pozostawienia kursora w pliku tuż obok tych 10 wierszy dla zwykłych plików. Problem może pojawić się w przypadkuhead
implementacji innych niż POSIX (bardzo stare wersje GNU head były w tym przypadku niezgodne, ale mówimy dekady) lub jeśli plik nie jest widoczny (np. Nazwany potok lub gniazdo, ale wtedy inne rozwiązanie miałoby ten sam problem).sudo sh -c '{ head; tail;} < /path/to/file'
{ head; tail; }
Rozwiązanie nie będzie działać na rurach (lub gniazd lub jakichkolwiek innych plików niż możliwy do przeszukania), ponieważhead
mogłyby zużywają zbyt dużo danych, jak to brzmi w blokach i nie może żądać z powrotem na rurze potencjalnie pozostawiając kursor wewnątrz pliku poza to, cotail
jest przeznaczona wybrać.Możesz więc użyć narzędzia, które odczytuje jeden znak naraz, takiego jak powłoka
read
(tutaj, używając funkcji, która przyjmuje liczbę linii nagłówka i linii ogona jako argumenty).lub zaimplementuj
tail
w awk na przykład jako:Z
sed
:(choć należy pamiętać, że niektóre
sed
implementacje mają niskie ograniczenie wielkości obszaru wzorców, więc zawiodłyby w przypadku dużych wartości liczby linii końcowych).źródło
Korzystając z
bash
podstawiania procesów, możesz wykonać następujące czynności:Zauważ, że linie nie są w porządku, chociaż w przypadku plików dłuższych niż około 8kB, prawdopodobnie będą. Ta wartość graniczna 8 kB jest typowym rozmiarem bufora odczytu i jest związana z przyczyną, dla
| {head; tail;}
której nie działa dla małych plików.Jest
cat >/dev/null
to konieczne, aby utrzymaćhead
rurociąg przy życiu. W przeciwnym razietee
wyjdzie wcześniej, a gdy otrzymasz dane wyjściowetail
, będzie ono pochodziło gdzieś pośrodku wejścia, a nie na końcu.Wreszcie, dlaczego
>/dev/null
zamiast, powiedzmy, przejśćtail
do innego|
? W następującym przypadku:head
Standardowe wejście jest podawane do potokutail
zamiast do konsoli, co wcale nie jest tym, czego chcemy.źródło
tail
musi działać dłużej, ale spodziewam się (i widzę), że kończy się to mniej więcej o połowę krótszym czasem.tee >(head) >(tail)
tych samych powodów (>(...)
które, nawiasem mówiąc, jest teraz funkcją ksh obsługiwaną teraz przez zarówno zsh jak i bash), używa również potoków. Możesz to zrobić,... | (trap '' PIPE; tee >(head) >(tail) > /dev/null)
ale nadal będą wyświetlane komunikaty o błędach uszkodzonych rurtee
.tail
który został zabity przez SIGPIPE, nie jesttee
itail
nie pisze do potoku. Więc musi to byćkill()
prawda? A dzieje się tak tylko wtedy, gdy używam|
składni.strace
mówi, żetee
to nie dzwonieniekill()
... więc możebash
?seq 100000 | tee >(head -n1) >(tail -n1) > /dev/null
Za pomocą
ed
(który wczyta cały plik do pamięci RAM):źródło
ed -s file <<< $'11,$-10d\n,p\nq\n'
Pierwsze rozwiązanie Stephane'a w funkcji, dzięki czemu można używać argumentów (działa w dowolnej powłoce Bourne'a lub POSIX):
Teraz możesz to zrobić:
To oczywiście zakłada, że patrzysz tylko na jeden plik i że rozwiązanie Stephane działa (niezawodnie) tylko na zwykłych (możliwych do przeglądania) plikach.
źródło
Dzięki opcji
-u
(--unbuffered
) GNUsed
możesz użyćsed -u 2q
jako niebuforowanej alternatywy dlahead -n2
:(head -n2;tail -n2)
kończy się niepowodzeniem, gdy ostatnie wiersze są częścią bloku danych wejściowych zużywanych przezhead
:źródło
Wpadłem dziś na coś takiego, gdzie potrzebowałem tylko ostatniej linii i kilku linii z przodu strumienia i wymyśliłem następujące.
Czytam to w następujący sposób: zainicjuj przestrzeń wstrzymania zawartością pierwszego wiersza, dodaj linie 2-3 w przestrzeni wstrzymania, w EOF dołącz ostatnią linię do przestrzeni wstrzymania, zamień przestrzeń wstrzymania i wzorca i wydrukuj wzór przestrzeń.
Być może ktoś, kto ma więcej
sed
niż -fu niż ja, może wymyślić, jak to uogólnić, aby wydrukować kilka ostatnich wierszy strumienia wskazanego w tym pytaniu, ale nie potrzebowałem tego i nie mogłem znaleźć łatwego sposobu na matematykę na podstawie$
adresu wsed
lub być może przez zarządzanie przestrzenią wstrzymania, aby po osiągnięciu pozostało tylko kilka ostatnich liniiEOF
.źródło
Możesz wypróbować Perla, jeśli go masz:
Działa to w przypadku większości plików, ale odczytuje cały plik do pamięci przed jego przetworzeniem. Jeśli nie znasz plasterków Perla, „0” w nawiasach kwadratowych oznacza „weź pierwszą linię”, a „-3 ...- 1” oznacza „weź trzy ostatnie linie”. Oba możesz dostosować do swoich potrzeb. Jeśli potrzebujesz przetwarzać naprawdę duże pliki (co jest „duże” może zależeć od twojej pamięci RAM i być może rozmiarów wymiany), możesz wybrać:
może być nieco wolniejszy, ponieważ tworzy plasterek przy każdej iteracji, ale jest niezależny od rozmiaru pliku.
Oba polecenia powinny działać zarówno w potokach, jak i ze zwykłymi plikami.
źródło