Skuteczne usuwanie nagłówka w miejscu dla dużych plików za pomocą sed?

24

Poniższe polecenia mogą zająć minuty, w zależności od rozmiaru pliku. Czy jest jakaś bardziej skuteczna metoda?

sed -i 1d large_file 
Cheng
źródło

Odpowiedzi:

34

Spróbuj edzamiast tego:

ed <<< $'1d\nwq' large_file

Jeśli ta „duża” oznacza około 10 milionów linii lub więcej, lepiej użyć tail. Nie jest w stanie edytować w miejscu, ale jego wydajność sprawia, że ​​brakowi można wybaczyć:

tail -n +2 large_file > large_file.new

Edytuj, aby pokazać różnice czasowe:

( awkkod dodany przez Jaypal, aby mieć czasy wykonania na tym samym komputerze (procesor 2,2 GHz).)

bash-4.2$ seq 1000000 > bigfile.txt # further file creations skipped

bash-4.2$ time sed -i 1d bigfile.txt
time 0m4.318s

bash-4.2$ time ed -s <<< $'1d\nwq' bigfile.txt
time 0m0.533s

bash-4.2$ time perl -pi -e 'undef$_ if$.==1' bigfile.txt
time 0m0.626s

bash-4.2$ time { tail -n +2 bigfile.txt > bigfile.new && mv -f bigfile.new bigfile.txt; }
time 0m0.034s

bash-4.2$ time { awk 'NR>1 {print}' bigfile.txt > newfile.txt && mv -f newfile.txt bigfile.txt; }
time 0m0.328s
człowiek w pracy
źródło
W takim przypadku tailwolę liczyć czas zarówno na usunięcie pierwszego wiersza, jak i zastąpienie bigfile.txtgo bigfile.new.
rozcietrzewiacz
@rozcietrzewiacz, masz rację. Dziękuję Ci. Zaktualizowano
manatwork
To jest naprawdę fajne! Zrobiłem to samo z awki otrzymałem następujący wynik[jaypal:~/Temp] seq 1000000 > bigfile.txt [jaypal:~/Temp] time awk 'NR>1 {print}' bigfile.txt >newfile.txt real 0m0.649s user 0m0.601s sys 0m0.033s
jaypal singh
1
@Jaypal, dodałem Twój kod do listy alternatyw. Na mojej maszynie było jeszcze szybciej. Dziwne, spodziewałem się awk, że występ będzie bliższy sed. (Uwaga dla siebie: nigdy nie oczekuj - przetestuj zamiast tego)
manatwork
To było najlepsze rozwiązanie w moim przypadku: tail -n +2 bigfile.txt > bigfile.new && mv -f bigfile.new bigfile.txt;używam jednego pliku z blokadą do śledzenia pojedynczej listy zadań wykorzystywanej przez wiele procesów. Zacząłem co początkowy plakat wykorzystane: sed -i 1d large_file . Powodowało to blokowanie pliku na 1-2 sekundy. tail/mvKombi kończy niemal natychmiast. Dziękuję Ci!
Chris Adams
6

Nie ma sposobu, aby skutecznie usunąć rzeczy z początku pliku. Usuwanie danych od początku wymaga ponownego zapisania całego pliku.

Obcinanie od końca pliku może być jednak bardzo szybkie (system operacyjny musi tylko dostosować informacje o rozmiarze pliku, ewentualnie usuwając nieużywane teraz bloki). Zasadniczo nie jest to możliwe, gdy próbujesz usunąć z nagłówka pliku.

Teoretycznie może być „szybki”, jeśli dokładnie usuniesz cały blok / zakres, ale nie ma do tego żadnych wywołań systemowych, więc będziesz musiał polegać na specyficznej dla systemu plików semantyce (jeśli taka istnieje). (Albo mam jakąś formę przesunięcia w pierwszym bloku / zasięgu, aby zaznaczyć prawdziwy początek pliku, chyba. Nigdy o tym nie słyszałem.)

Mata
źródło
Jeśli plik jest bardzo duży, narzut We / Wy prawdopodobnie będzie (prawdopodobnie znacznie) większy niż narzut CPU wymagany do przetworzenia końca linii.
Mat.
Masz rację. Jednak może istnieć różnica w sposobie, w jaki narzędzia uzyskują dostęp do zawartości pliku. Najlepiej jest nie przetwarzać linii po linii, gdy nie jest to konieczne, lub przynajmniej nie czytać linii po linii, gdy nie jest to konieczne.
manatwork
2
Dziwię się, że różnica jest tak duża w twoich wynikach i mogę odtworzyć ją z tym rozmiarem pliku tutaj. Korzyści wydają się maleć wraz ze wzrostem wielkości pliku (wypróbowane z sekw. 10M, 15s dla sed, 5s dla ed). W każdym razie dobre wskazówki (+1).
Mat.
Począwszy od wersji 3.15, Linux ma teraz interfejs API do zwijania części pliku w systemach plików opartych na pewnym zakresie, ale przynajmniej dla ext4, które można wykonać tylko na pełnych blokach (zwykle 4k).
Stéphane Chazelas
Nawet jeśli edycja wymaga przepisania całego pliku, czasami bardzo przydatne jest posiadanie narzędzi wiersza poleceń do wydajnej edycji. W moim przypadku pomogło to, gdy musiałem usunąć pierwszy wiersz pliku, który był większy niż moja całkowita pamięć RAM systemu.
Jason
3

Najbardziej wydajna metoda, nie rób tego! Jeśli tak, to w każdym razie potrzebujesz dwa razy więcej „dużego” miejsca na dysku i marnujesz operacje wejścia / wyjścia.

Jeśli utknąłeś z dużym plikiem, który chcesz odczytać bez pierwszej linii, poczekaj, aż będziesz musiał go przeczytać w celu usunięcia pierwszej linii. Jeśli chcesz wysłać plik ze standardowego programu do programu, użyj tail, aby to zrobić:

tail -n +2 | your_program

Gdy potrzebujesz odczytać plik, możesz skorzystać z okazji, aby usunąć pierwszą linię, ale tylko jeśli masz potrzebne miejsce na dysku:

tail -n +2 | tee large_file2 | your_program

Jeśli nie możesz czytać ze standardowego wejścia, użyj fifo:

mkfifo large_file_wo_1st_line
tail -n +2 large_file > large_file_wo_1st_line&
your_program -i large_file_wo_1st_line

jeszcze lepiej, jeśli używasz bash, skorzystaj z substytucji procesu:

your_program -i <(tail -n +2 large_file)

Jeśli potrzebujesz szukać w pliku, nie widzę lepszego rozwiązania niż nie utknięcie w pliku. Jeśli ten plik został wygenerowany przez stdout:

large_file_generator | tail -n +2 > large_file

W przeciwnym razie zawsze istnieje rozwiązanie FIFO lub proces zastępowania procesów:

mkfifo large_file_with_1st_file
large_file_generator -o large_file_with_1st_file&
tail -n +2 large_file_with_1st_file > large_file_wo_1st_file

large_file_generator -o >(tail -n 2+ > large_file_wo_1st_file)
jfg956
źródło
1

Możesz używać Vima w trybie Ex:

ex -sc '1d|x' large_file
  1. 1 wybierz pierwszą linię

  2. d kasować

  3. x Zapisz i zamknij

Steven Penny
źródło
0

To tylko teoria, ale ...

Niestandardowy system plików (zaimplementowany za pomocą FUSE lub podobnego mechanizmu) może ujawnić katalog, którego zawartość jest dokładnie taka sama, jak już istniejący katalog gdzie indziej, ale z plikami obciętymi, jak chcesz. System plików przetłumaczy wszystkie przesunięcia plików. W takim przypadku nie trzeba wykonywać czasochłonnego przepisywania pliku.

Ale biorąc pod uwagę, że ten pomysł jest bardzo trywialny, chyba że masz dziesiątki terabajtów takich plików, wdrożenie takiego systemu plików byłoby zbyt drogie / czasochłonne, aby było praktyczne.

liori
źródło