Tek bir büyük metin dosyasında birden çok arama ve değiştirme işlemi


11

Büyük bir metin dosyam var (yaklaşık 2GB). Aynı dosya üzerinde beş arama ve değiştirme eylemi yapmak istiyorum ve bunu tek bir komutta yapmak istiyorum. Normalde vim kullanıyorum, dosyayı açıyorum, bir değiştirme eylemi yapıyorum, sonra bir sonraki, vb. Bir veya üç aramadan sonra vim'in bellek sorunları nedeniyle çöktüğünü fark ettiğim için bir yakalama var.

İşte Vim'de kullandığım komutun iki örneği:

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

Bununla başa çıkmanın en iyi yolu nedir?

Yanıtlar:


8

Bu şekilde sed kullanırdım:

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

-iseçeneği "yerinde" değiştirme anlamına gelir. Sed'e, bu seçeneğe bir uzantı sağlayan bir dosya yedeği oluşturmasını söyleyebilirsiniz (dosya.txt dosyanızı -i.bakdosya.txt.bak olarak yedekler).


Çok hızlı! Sadece cevabınız değil ;-) ama 5 arama ve değiştirme ile bu komut dosyası sadece vim içinde açılış olarak yaklaşık 10 kat daha hızlı. Bir şey beni şaşırttı. İlk başta .bak dosyasının düzenlenmiş dosya olacağını düşündüm, ancak elbette orijinal.
SPRBRN

Tek seferde 2 GB'lık bir dosyada on arama ve değiştirme işlemi (binlerce isabetle), bellek sorunu yok. Ortalama bir masaüstünde iki dakikadan az - süper!
SPRBRN

Bir soru ... Değiştirme dizesindeki noktalardan kaçıyorsunuz. Bu gerekli mi?
SPRBRN

1
Hoşgeldin @rxt :) Aslında haklısın, içindeki dizede kaçan noktaları kullanabilirsiniz sed. Denedim ve işe yarıyor. Unix ve Linux Stackexchange'te iyi bir iş parçacığı var ve kabul edilen cevap, kaçacak karakterler olarak noktalardan bahsetmiyor.
ssssteffff

2
@rxt dize yerine söyledin , üzgünüm, hayır orada kaçmak gerekmez.
terdon

6

Daha fazla arama deseniniz varsa, bunları bir dosyaya kaydedebilir ve değiştirmeleri oradan okuyabilirsiniz. Örneğin, bunların aşağıdakilerin içeriği olduğunu varsayalım replacements.txt:

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

Daha sonra N değişikliklerinin bir listesini okuyabilir ve bunları bununla değiştirebilirsiniz:

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

NOTLAR:

  • Bu, arama dizelerinizin boşluk içermediğini ve garip karakterlerin kaçması gerektiğini varsayar replacements.txt.
  • sedBirçok değiştirme işleminiz varsa, her değiştirme için bir tane çalışacaktır .
  • Biraz daha zaman alacağına aldırmazsanız, rastgele sayıda değiştirmeyle (binlerce veya milyonlarca veya herhangi bir şey) başa çıkabilir.

Başka bir seçenek, yukarıdakileri sedkomut dosyası olarak yazmak olacaktır :

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;

Daha sonra komut dosyasını dosyanızda çalıştırabilirsiniz ve tüm değiştirmeleri tek seferde yapar:

sed -f replace.sed infile.txt 

Diğer seçenek için +1 ''. Değiştirmelerin bir dosyada saklanması kullanışlı olabilir! (Umarım hatırlayacağım ...)
mpy

Özel komut dosyası yerine yerel işlevler kullandığı için "diğer seçenek" için +1, bu nedenle daha taşınabilir / paylaşılabilir
David Cook

@DavidCook teşekkürler, ancak diğerinden daha yerel veya taşınabilir değil. İlk yaklaşım bir POSIX kabuk döngüsü kullanmak, ikincisi kadar taşınabilir. Bir kabuk döngüsü kullandığından çok daha yavaş olacaktır.
terdon

Haklısın, demek istediğim, sed komut dosyası biçiminin daha taşınabilir olması, çünkü replacements.txt dosyasının yanında paylaşılması gereken bir komut dosyası yerine yerleşik sed işlevini kullanmasıdır. Yine de, her ikisi de harika seçenekler!
David Cook
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.