Jak wyświetlić niektóre wiersze z pliku tekstowego w systemie Linux?


85

Chyba każdy zna przydatne narzędzia Linuksa do cmd headi tail. headpozwala wydrukować pierwsze X wierszy pliku, tailrobi to samo, ale drukuje koniec pliku. Jakie jest dobre polecenie, aby wydrukować środek pliku? coś w stylu middle --start 10000000 --count 20(wydrukuj 10 000 000 do 10 000 000 linii).

Szukam czegoś, co skutecznie poradzi sobie z dużymi plikami. Próbowałem tail -n 10000000 | head 10i to jest strasznie wolne.


Odpowiedzi:


111
sed -n '10000000,10000020p' filename

Możesz być w stanie trochę to przyspieszyć:

sed -n '10000000,10000020p; 10000021q' filename

W tych poleceniach opcja -npowoduje sed„pomijanie automatycznego drukowania przestrzeni wzorów”. pPolecenia „print [s] obecna przestrzeń wzór” i qpolecenie „Natychmiast zamknąć [s] z sed skryptu bez przetwórstwa więcej wejście ...” Te cytaty pochodzą ze sed manstrony .

Nawiasem mówiąc, twoje polecenie

tail -n 10000000 filename | head 10

zaczyna się od dziesiątej milionowej linii od końca pliku, podczas gdy twoje polecenie „środkowe” wydaje się zaczynać od dziesiątej milionowej liczby od początku, co byłoby równoważne z:

head -n 10000010 filename | tail 10

Problem polega na tym, że w przypadku nieposortowanych plików o wierszach o zmiennej długości każdy proces będzie musiał przejść przez liczenie plików nowego wiersza. Nie można tego skrócić.

Jeśli jednak plik zostanie posortowany (na przykład plik dziennika ze znacznikami czasu) lub ma linie o stałej długości, możesz wyszukać plik na podstawie pozycji bajtu. W przykładzie pliku dziennika możesz wyszukiwać binarnie przedział czasu, tak jak robi to mój skrypt Python tutaj *. W przypadku pliku o stałej długości rekordu jest to naprawdę łatwe. Po prostu szukasz linelength * linecountznaków do pliku.

* Wciąż zamierzam opublikować kolejną aktualizację tego skryptu. Może kiedyś się tym zajmę.


Oto sedwersja Karola middlefunkcji: middle() { local s=$1 c=$2; shift 2; sed -n "$s,$(($s + $c -1))p; $(($s + $c))q" "$@"; }. Będzie obsługiwał wiele argumentów plików, nazwy plików ze spacjami itp. Wiele plików jest przetwarzanych razem, tak jakby były one przechwytywane w taki sam sposób, jak sedzwykle (tak więc środkowy 1000 100 plik1 plik2 rozciągałby się od końca pierwszego pliku do początku drugiego, jeśli pierwszy ma mniej niż 1100 linii).
Dennis Williamson,

Funkcja w moim poprzednim komentarzu może być wywołana z parametrem nazwy pliku: middle startline count filenamelub wieloma nazwami plików: middle startline count file1 file2 file3lub z przekierowaniem: middle startline count < filenamelub w potoku: some_command | środkowa liczba linii startowych lubcat file* | middle startline count
Dennis Williamson

Czy „w twoim poleceniu sed nie powinno być”? Nie mogę zmusić go do działania z backtick, ale działa dobrze z pojedynczym cytatem.
Ian Hunter,

@beanland: Tak, to literówka. Naprawiłem to. Dzięki.
Dennis Williamson,

1
@kev: Dodałem wyjaśnienie do mojej odpowiedzi.
Dennis Williamson,

28

Dowiedziałem się o następującym zastosowaniu sed

sed -n '10000000,+20p'  filename

Mam nadzieję, że komuś się przyda!


Dobrze wiedzieć, że istnieje alternatywa dla argumentu ostatniej linii zaproponowanego przez Dennisa: linia jest liczona jako drugi sed -nargument, co czyni ją dość czytelną.
user3123159

Przykładowe użycie: extract_lines(){sed -n "$1,+$2p" <file>}które zapisuje na standardowe wyjście.
user3123159

4

To mój pierwszy post tutaj! W każdym razie ten jest łatwy. Powiedzmy, że chcesz pobrać linię 8872 z pliku o nazwie file.txt. Oto jak to zrobić:

cat -n plik.txt | grep „^ * 8872”

Teraz pytanie brzmi: po 20 wierszach. Aby to osiągnąć, robisz

cat -n plik.txt | grep -A 20 '^ * 8872'

Dla linii wokół lub przedtem zobacz flagi -B i -C w instrukcji grep.


Chociaż jest to technicznie poprawne i interesujący sposób, aby to zrobić na pliku o rozsądnych rozmiarach, jestem ciekawy jego skuteczności podczas pracy z plikami o rozmiarze, o który pyta plakat.
Jenny D.

Wiele linii: cat -n plik.txt | grep "^ \ s \ + (10 \ | 20 \ | 30) \ s \ +"
Jeffrey Knight

cat -n file.txt | grep '^ *1'wydaj wszystkie linie, które mają 1 po prawej stronie. Jak wydrukować wiersz 1 za pomocą tej techniki? Wiem, że mogę skierować -n 1 .... ale jak używać grep?
Sean87

1

Sedn odpowiedź Dennisa jest właściwą drogą. Ale używając tylko głowy i ogona, pod uderzeniem:

middle () {head -n $ [1 $ + 2 $] | ogon - 2 USD; }

To skanuje dwa pierwsze wiersze 1 $ + 2 $, więc jest znacznie gorsze niż odpowiedź Dennisa. Ale nie musisz pamiętać tych wszystkich liter, aby z niego skorzystać ....


Używanie $[...]jest przestarzałe, przynajmniej w Bash. Ponadto brakuje parametru pliku.
Dennis Williamson,

@Dennis: Nie brakuje parametru: masz go użyć na standardowym interfejsie, zgodnie z middle 10 10 < /var/log/auth.log.
Charles Stewart,

1

Użyj następującego polecenia, aby uzyskać określony zakres linii

awk 'NR < 1220974{next}1;NR==1513793{exit}' debug.log | tee -a test.log

Tutaj debug.log to mój plik, który składa się z braków linii i użyłem do wydrukowania linii z numeru linii 1220974 do 1513793 do pliku test.log. mam nadzieję, że będzie to pomocne w przechwytywaniu zakresu linii.


Ta sama odpowiedź, co serverfault.com/a/641252/140016 . Doceniony.
Deer Hunter

To nie jest ta sama odpowiedź. Powinno to być szybsze w przypadku dużych plików, ponieważ faktycznie przerywa się po wydrukowaniu ostatniego wiersza zamiast kontynuowania skanowania pliku.
fobiczny

0

Rubinowa wersja oneliner.

ruby -pe 'next unless $. > 10000000 && $. < 10000020' < filename.txt

Może być komuś przydatny. Rozwiązania z „sed” dostarczone przez Dennisa i Dox są bardzo fajne, nawet jeśli wydają się szybsze.


0

Możesz użyć „nl”.

nl filename | grep <line_num>

0

Na przykład ten awk wydrukuje linie od 20 do 40

awk '{if ((NR> 20) i& (NR <40)) print 0 $}' / etc / passwd


0

Jeśli znasz numery linii, powiedz, że chcesz pobrać linie 1, 3 i 5 z pliku, powiedz / etc / passwd:

perl -e 'while(<>){if(++$l~~[1,3,5]){print}}' < /etc/passwd

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.