Wiele operacji wyszukiwania i zamiany w jednym dużym pliku tekstowym

11

Mam duży plik tekstowy (około 2 GB). Chcę wykonać pięć operacji wyszukiwania i zamiany w tym samym pliku i chciałbym to zrobić w jednym poleceniu. Zwykle używam vima, otwieram plik, wykonuję jedną akcję zamiany, potem następną itd. Jest jeden haczyk, ponieważ zauważyłem, że po trzech lub czterech wyszukiwaniach vim ulega awarii z powodu problemów z pamięcią.

Oto dwa przykłady polecenia, którego używam w Vimie:

:%s/www\.abcdef/www.test.abcdef/g 
:%s/www\.klmnop/www.test.klmnop/g

Jaki jest najlepszy sposób, aby sobie z tym poradzić?

SPRBRN
źródło

Odpowiedzi:

8

Użyłbym sed tak:

sed -i "s/www\.abcdef/www.test.abcdef/g;s/www\.kmlnop/www.test.klmnop/g;" yourfile.txt

-iopcja oznacza zastąpienie „na miejscu”. Możesz powiedzieć sedowi, aby utworzył kopię zapasową pliku, podając rozszerzenie tej opcji ( -i.bakutworzy kopię zapasową pliku twojplik.txt jako twój plik.txt.bak).

ssssteffff
źródło
To szybko! Nie tylko twoja odpowiedź ;-), ale ten skrypt z 5 wyszukiwaniem i zamienianiem jest około 10 razy szybszy niż samo otwieranie pliku w vimie. Jedno mnie jednak pomyliło. Na początku myślałem, że plik .bak będzie plikiem edytowanym, ale oczywiście jest to oryginał.
SPRBRN
Dziesięć akcji wyszukiwania i zamiany (z tysiącami trafień) w pliku 2 GB za jednym razem, bez problemów z pamięcią. Średnio mniej niż dwie minuty na pulpicie - super!
SPRBRN
Jedno pytanie ... Uciekasz kropkom w ciągu zastępującym. Czy to konieczne?
SPRBRN
1
Nie ma za co @rxt :) Właściwie masz rację, możesz użyć kropek bez znaku ucieczki w ciągu zastępującym w sed. Próbowałem i to działa. W Unix i Linuxie Stackexchange jest dobry wątek , a zaakceptowana odpowiedź nie wymienia kropek jako znaków do ucieczki.
ssssteffff,
2
@rxt powiedziałeś, że zamień ciąg, przepraszam, nie, nie musisz tam uciekać.
terdon
6

Jeśli masz wiele innych wzorców wyszukiwania, możesz zapisać je w pliku i odczytać z niego podstawienia. Powiedzmy, że są to replacements.txt:

www\.abcdef www.test.abcdef 
www\.klmnop www.test.klmnop

Następnie możesz przeczytać listę N zamienników i zastąpić je następującymi:

while read from to; do
  sed -i "s/$from/$to/" infile.txt ; 
done < replacements.txt 

UWAGI:

  • Zakłada się, że wyszukiwane ciągi nie zawierają spacji i że należy uciec od wszelkich dziwnych znaków replacements.txt.
  • Będzie działać jeden sedna wymianę, co może zająć trochę czasu, jeśli wykonujesz wiele operacji wymiany.
  • Może poradzić sobie z dowolną liczbą zamienników (tysiące, miliony lub cokolwiek innego), o ile nie masz nic przeciwko, że zajmie to trochę więcej czasu.

Inną opcją byłoby napisanie powyższego jako sed skryptu:

s/www\.abcdef/www\.test\.abcdef/g;
s/www\.kmlnop/www\.test\.klmnop/g;
s/aaaa/bbbb/g;
s/cccc/dddd/g;
s/eeee/ffff/g;

Następnie możesz uruchomić skrypt na swoim pliku, a wszystkie zmiany zostaną wykonane za jednym razem:

sed -f replace.sed infile.txt 
terdon
źródło
+1 dla ,, innej opcji ''. Przydatne może być przechowywanie zamienników w pliku! (Mam nadzieję, że to zapamiętam ...)
mpy
+1 za „inną opcję” również dlatego, że wykorzystuje natywną funkcjonalność zamiast niestandardowego skryptu, więc jest bardziej przenośny / dostępny
David Cook
@DavidCook dzięki, ale nie jest bardziej natywny ani przenośny niż inne. Pierwsze podejście polega na użyciu pętli powłoki POSIX, jest dokładnie tak samo przenośne jak drugie. Będzie po prostu znacznie wolniejszy, ponieważ używa pętli powłoki.
terdon
Masz rację, miałem na myśli to, że format pliku skryptu sed jest bardziej przenośny, ponieważ wykorzystuje on wbudowaną funkcjonalność sed zamiast skryptu, który musiałby być udostępniany obok pliku replaceements.txt. Niemniej jednak oba są świetnymi opcjami!
David Cook