Zamień tekst szybko w bardzo dużym pliku

25

Mam plik tekstowy o pojemności 25 GB, który wymaga zastąpienia ciągu tylko w kilku wierszach. Mogę używać z sedpowodzeniem, ale uruchomienie zajmuje bardzo dużo czasu.

sed -i 's|old text|new text|g' gigantic_file.sql

Czy jest na to szybszy sposób?

eisaacson
źródło
Czy znasz numery wierszy, w których znajduje się tekst do zastąpienia? Jeśli nie jedyną możliwością przyspieszenia jest uzyskanie szybszego komputera. Fakt, że masz dużą ilość danych, oznacza, że ​​ich przeszukanie zajmie dużo czasu.
David King
Potrafię szybko wyszukać numery linii, więc tak.
eisaacson
Możesz także użyć wielu rdzeni procesora, aby go przyspieszyć - rankfocus.com/use-cpu-cores-linux-commands
ahaswer
Nie używaj sed do dużych plików. Zamiast tego spójrz na vi lub vim .
MikeJRamsey56

Odpowiedzi:

26

Możesz spróbować:

sed -i '/old text/ s//new text/g' gigantic_file.sql

Z tego ref :

OPTYMALIZACJA PRĘDKOŚCI: Jeśli trzeba zwiększyć szybkość wykonywania (z powodu dużych plików wejściowych lub powolnych procesorów lub dysków twardych), podstawienie zostanie wykonane szybciej, jeśli podano wyrażenie „find” przed podaniem „s /.../. ../ ”.

Oto porównanie pliku 10G. Przed:

$ time sed -i 's/original/ketan/g' wiki10gb
real    5m14.823s
user    1m42.732s
sys     1m51.123s

Po:

$ time sed -i '/ketan/ s//original/g' wiki10gb
real    4m33.141s
user    1m20.940s
sys     1m44.451s
mkc
źródło
Ostatnia sedjest błędna. Wczoraj edytowałem ten post, aby naprawić ostatnie sedpolecenie, które powinno być, time sed -i '/original/ s//ketan/g' wiki10gba nie nie time sed -i '/ketan/ s//original/g' wiki10gb. Cofam dzisiaj swoją edycję, ponieważ 1. czasy nie są już zgodne z poleceniem i 2. Zrobiłem ten sam test z GNU sed na pliku ponad 3 GB i nie widzę żadnej różnicy między tymi dwiema sedalternatywami. Podejrzewam, że różnica w czasie wynika z błędnej pisowni.
xhienne
@xhienne Nie jestem pewien, co masz na myśli przez literówkę. W pierwszym etapie zastępuję słowo „oryginał” słowem „ketan”, aw drugim zastępuję termin „ketan” terminem „oryginał”, co skutkuje taką samą liczbą podstawień w obu przypadkach.
mkc
1
Stosowałem „poprawkę” zgłoszoną przez nowego użytkownika o niewystarczającej reputacji. Teraz rozumiem, co zrobiłeś. Jeśli jednak chcesz udowodnić, że jedna składnia jest lepsza od siebie, musisz wykonać dokładnie tę samą operację, co nie ma tu miejsca (pod względem procesora szukanie ciągu 5 znaków nie jest tym samym, co szukanie ciągu Ciąg 7 znaków). Co więcej, ten rodzaj testu pliku 10 GB jest silnie uzależniony od obciążenia komputera (procesora, dysku). Widziałem wiele wahań w timewynikach osobiście, ale w sumie nie było różnicy w czasie.
xhienne
Wierzę, że jest to powiązane - patrz zaakceptowana odpowiedź tutaj, stackoverflow.com/questions/11145270/... >> sed przesyła strumieniowo cały plik, ale jak zaznaczono w tej odpowiedzi, podanie numeru linii (jeśli jest znana) pomaga: w moim przypadku , ~ 2-krotny wzrost szybkości wykonywania (GNU sed 4.5). Możesz grep -n lub ripgrep (rg), aby znaleźć numery linii na podstawie wyszukiwania wzorców. W efekcie określenie numeru wiersza jest jak wynik wyszukiwania w tym pliku, zgodnie z powyższą odpowiedzią.
Victoria Stuart
1

Krótka odpowiedź brzmi „nie” - twoim ograniczeniem dla tego rodzaju operacji jest IO dysku. Nie ma możliwości szybszego strumieniowania 25 GB dysku. Możesz uzyskać niewielką poprawę, jeśli nie wprowadzisz edycji w miejscu, a wynik zapisujesz na sedosobnym dysku (jeśli masz jeden dostępny) - ponieważ w ten sposób możesz czytać z jednego, jednocześnie pisząc na innym i jest nieco w rezultacie mniej rywalizacji.

Państwo może być w stanie przyspieszyć go trochę nie używając silnika regex dla każdej linii - tak na przykład przy użyciu Perl (Jestem całkiem pewien, że można to zrobić sed, ale nie wiem składni) - ten rozpocznie się od linia 10 000 wzwyż.

perl -pe '$. > 10_000 && s/old_text/new_text/g' 

A jeśli występują jakieś komplikacje w RE (metaznaki), wówczas ich minimalizacja nieznacznie poprawi wydajność silnika regex.

Sobrique
źródło
1
W sed to byłobysed -i '10000,$ s/old_text/new_text/g'
Dani_l
Śliczny. Nie wiem, jak się sedporównuje - zakładam nieznacznie szybciej, ale niewiele z powodu rozmiaru pliku.
Sobrique
Zakładam, że perl jest szybszy niż sed, ale sed jest nieco mniej tajemniczy, a raczej wymaga mniej wstępnej krzywej uczenia się.
Dani_l
1
Patrz, teraz bym powiedział odwrotnie - można (prawie) zapisu sedw perl, ale ten pozwala również napisać bardziej gadatliwy skryptów też.
Sobrique
0

Jeśli nowy i stary tekst mają tę samą długość, możesz wyszukiwać w pliku i zapisywać tylko zmienione bajty, zamiast kopiować cały plik. W przeciwnym razie jesteś uwięziony w przenoszeniu dużej ilości danych.

Uwaga: jest to trudne i wymaga napisania niestandardowego kodu.

Zobacz stronę podręcznika fseek, jeśli pracujesz w C lub C ++, lub swoje ulubione języki do wyszukiwania i pisania wywołań systemowych.

Jeśli nalegasz na używanie tylko wiersza poleceń i możesz uzyskać bajtowe przesunięcia tekstu, możesz napisać tekst zastępczy za pomocą starannie napisanych poleceń „dd”.

skradzione
źródło