Mam plik zawierający około 10 milionów linii.
Chcę usunąć wszystkie wiersze w pliku, które mają mniej niż sześć znaków.
Jak mam to zrobic?
command-line
text-processing
Powiedz mi dlaczego
źródło
źródło
Odpowiedzi:
Istnieje wiele sposobów, aby to zrobić.
Używanie
grep
:Teraz
out.txt
będzie zawierać wiersze mające sześć lub więcej znaków.Odwrotna droga:
Używanie
sed
, usuwanie linii o długości 5 lub mniejszej:Odwrotnie, drukowanie linii o długości sześciu lub większej:
Możesz zapisać dane wyjściowe w innym pliku za pomocą
>
operatora podobnegogrep
lub edytować plik w miejscu za pomocą-i
opcjised
:Kopia zapasowa oryginalnego pliku zostanie utworzona,
file.txt.bak
a zmodyfikowany plik będziefile.txt
.Jeśli nie chcesz przechowywać kopii zapasowej:
Używając powłoki, Wolniej, nie rób tego , to tylko w celu pokazania innej metody:
Korzystanie
python
nawet wolniej niżgrep
,sed
:Lepsze wykorzystanie rozumienia listy, aby być bardziej Pythonicznym:
źródło
To jest bardzo proste:
Jest to niezwykle wydajne, ponieważ
grep
nie będzie parsowało więcej niż potrzebuje, ani nie interpretuje znaków w żaden sposób: po prostu wysyła (całą) linię do standardowego wyjścia (które powłoka przekierowuje do pliku wynikowego), gdy tylko zobaczy 6 znaki w tej linii (.
w kontekście wyrażenia regularnego dopasowuje dowolny 1 znak).Zatem grep wypisuje tylko wiersze zawierające 6 (lub więcej) znaków, a pozostałe nie są wyprowadzane przez grep, więc nie robią tego z plikiem wynikowym.
źródło
Rozwiązanie nr 1: Używając C.
Najszybszy sposób: skompiluj i uruchom ten program C:
Skompiluj z
gcc program.c -o program
, uruchom z./program file line_length
(gdziefile
= ścieżka do pliku iline_length
= minimalna długość linii, w twoim przypadku6
; maksymalna długość linii jest ograniczona do1000000
znaków na linię; możesz to zmienić, zmieniając wartośćMAX_BUFFER_SIZE
).(Trick zastąpił
\n
ze\0
znalezionych tutaj ).Porównanie ze wszystkimi innymi rozwiązaniami zaproponowanymi w tym pytaniu, z wyjątkiem rozwiązania powłoki (uruchomienie testowe na pliku ~ 91 MB z liniami 10M o średniej długości 8 znaków):
Rozwiązanie nr 2: Korzystanie z AWK:
length>=6
: jeślilength>=6
zwraca PRAWDA, drukuje bieżący rekord.Rozwiązanie nr 3: Używając Perla:
lenght>=6
zwróci wartość PRAWDA, drukuje bieżący rekord.źródło
awk
rozwiązanie ..sed
rozwiązanie (zdarza się, wiem). XDpos
zmiennej? Rozumiem, że zwraca wskaźnik do znakuline
ze znakiem nowej linii, ale wydaje się, że nigdy go nie używasz. A jeśli go nie znajdziesz, po prostu ustaw go na równy\0
.\0
(strchr()
zwraca wskaźnik NULL jeżeli znak nie został znaleziony). Chodzi o to, aby zastąpić każdą nową linię na końcu każdej linii,\0
tak aby nowa linia nigdy nie była liczona przezstrlen()
: jest to tak, że długość zawsze można porównać do 6, niezależnie od potencjalnie brakującej nowej linii w ostatniej linii. Wiem, że inne traktowanie tylko ostatniej linii byłoby znacznie bardziej wydajne. Prawdopodobnie zaktualizuję to później.grep
rozwiązanie dla tego samego pliku i jest ono rzeczywiście szybsze (prawdopodobnie dlatego, żestrlen()
nie jest to najlepszy pomysł tutaj) . Spróbuję użyćgetchar()
pętli, aby zamiast tego sprawdzić tylko pierwszą literę N, myślę, że powinna to wyraźnie poprawić. I tak, każda linia powyżej długości bufora jest po prostu przycięta do długości bufora.Możesz używać Vima w trybie Ex:
\v
włącz magię.{6}
znajdź wiersze z co najmniej 6 znakamiv
Odwróć wybórd
usunąćx
Zapisz i zamknijźródło
Rozwiązanie Ruby:
Prosty pomysł: przekieruj plik do standardowego ruby i wypisz linię ze standardowego, tylko jeśli jego długość jest większa lub równa 6
źródło