Nasıl grep ve değiştirilir


254

Özyinelemeli bir dizinde tüm dosyaları ve alt dizinleri içinde belirtilen bir dize aramak ve bu dize başka bir dize ile değiştirmek gerekir.

Bunu bulmak için komut şöyle görünebilir biliyorum:

grep 'string_to_find' -r ./*

Ancak her örneğini string_to_findbaşka bir dizeyle nasıl değiştirebilirim ?


Grep'in bunu yapabileceğine inanmıyorum (yanlış olabilirim). Değiştirmek için sed veya perl kullanmak daha kolay yollardır
Memento Mori

2
sed -i 's/.*substring.*/replace/'
Kullanmaya

2
@Eddy_Em Bu, tüm satırı replace ile değiştirir. Alt dizeden önce ve sonra çizginin bir bölümünü yakalamak için gruplandırmayı kullanmanız ve ardından bunu yedek satıra koymanız gerekir. sed -i 's/\(.*\)substring\(.*\)/\1replace\2/'
JStrahl


Yanıtlar:


250

Başka bir seçenek bulmak ve sonra sed geçmesi kullanmaktır.

find /path/to/files -type f -exec sed -i 's/oldstring/new string/g' {} \;

34
OS X 10.10 Terminalinde, parametreye uygun bir uzatma dizesi -igereklidir. Örneğin, find /path/to/files -type f -exec sed -i "" "s/oldstring/new string/g" {} \;Neyse, boş dize sağlamak el kitabında tarif edildiği gibi bir yedekleme dosyası oluşturur ...
Eonil

10
Neden "sed: RE hatası: geçersiz bayt dizisi" alıyorum. Ve evet, -i ""OS X için ekledim . Aksi çalışır.
taco

2
MacOS 10.12'de geçersiz bayt sırası sorunu vardı ve bu soru / cevap sorunumu çözdü: stackoverflow.com/questions/19242275/… .
abeboparebop

3
Bu, her dosyaya dokunur, böylece dosya süreleri değiştirilir; ve dönüşüm gelen Satır sonlarına CRLFkadar LFWindows üzerinde.
jww

183

Cevabı aldım.

grep -rl matchstring somedir/ | xargs sed -i 's/string1/string2/g'

14
Bu eşleşen dosyaları iki kez tarar ... bir kez grepve sonra tekrar sed. findYöntemi kullanmak daha verimlidir ancak bahsettiğiniz bu yöntem işe yarar.
cmevoli

41
OS X'te değiştirmek gerekecektir sed -i 's/str1/str2/g'için sed -i "" 's/str1/str2/g'çalışmalarına bunun için.
jdf

6
@cmevoli bu yöntemle greptüm dosyaları gözden geçirir ve sedsadece eşleşen dosyaları tarar grep. İle finddiğer yanıtında yöntemle, findilk listeleri sonra tüm dosyaları ve sedbu dizindeki tüm dosyalar arasında tarar. Bu yöntem mutlaka yavaş değil Yani, kaç maç bağlıdır ve aralarında arama hızları arasındaki farklar sed, grepve find.
joelostblom

4
OTOH bu şekilde, grep'in aslında değiştirmeden ÖNCE ne bulduğunu ÖNİZLEMEK sağlar, özellikle benim gibi regex n00bs için başarısızlık riskini büyük ölçüde azaltır
Lennart Rolland

2
Bu, grep değiştirme işleminiz sed'den daha akıllı olduğunda da yararlıdır. Örneğin ripgrep .gitignore'a uyurken sed yapmaz.
user31389

44

Hatta böyle yapabilirsin:

Misal

grep -rl 'windows' ./ | xargs sed -i 's/windows/linux/g'

Bu , geçerli dizine göre tüm dosyalarda ' windows ' dizesini arar ve her dosyadaki dizenin her oluşumu için ' windows ' yerine ' linux ' değiştirir .


2
grepDeğiştirilmemelidir dosya varsa sadece yararlıdır. sedTüm dosyalar üzerinde çalışırken dosyanın değişiklik tarihi güncellenir, ancak eşleşme yoksa içeriği değiştirilmez.
üçlü

@tripleee: Dikkatli olun ... ama [sed] eşleşme yoksa içeriği değişmeden bırakın " . Kullanırken -i, sediçerik değişmediği halde dokunduğu her dosyanın dosya süresini değiştirdiğine inanıyorum . sedsatır sonlarını da dönüştürüyor sedGit CRLFLF
depoda

En azından macosx'ta, yerinde değişiklik gerçekleştikten sonra hiçbir yedekleme dosyasının yapılmayacağını belirtmek için -i'den sonra bu komutun "" girmesi gerekir. Ayrıntılar için kılavuz sayfasına bakın. Yedek almak isterseniz, dosyanın uzantısının oluşturulacağı yer burasıdır.
spinyBabbler

31

Bu benim için en iyi OS X'te çalışır:

grep -r -l 'searchtext' . | sort | uniq | xargs perl -e "s/matchtext/replacetext/" -pi

Kaynak: http://www.praj.com.au/post/23691181208/grep-replace-text-string-in-files


bu harika! Ayrıca ag ile çalışır:ag "search" -l -r . | sort | uniq | xargs perl -e 's/search/replace' -pi

@sebastiankeller Perl komutunuzda, bir sözdizimi hatası olan son eğik çizgi yoktur.
üçlü

3
Neden bunun bir sort -uparçası? Hangi durumlarda grep -rlaynı dosya adını iki kez üretmeyi beklersiniz ?
tripleee

5

Diğer çözümler normal ifade sözdizimlerini karıştırır. Hem arama hem de değiştirme için perl / PCRE kalıplarını kullanmak ve yalnızca eşleşen dosyaları işlemek için, bu oldukça iyi çalışır:

grep -rlZPi 'match1' | xargs -0r perl -pi -e 's/match2/replace/gi;'

burada match1ve match2genellikle aynıdır, ancak match1yalnızca ikame ile ilgili daha gelişmiş özellikleri kaldırmak için basitleştirilebilir, örneğin yakalama grupları.

Çeviri: grepözyinelemeli olarak ve dosya adındaki herhangi bir özel karakteri korumak için nul ile ayrılmış dosyaları yinelemeli olarak listeleyin ve ardından xargsnul ile ayrılmış bir liste bekleyen dosya adlarını ekleyin, ancak hiçbir ad alınmazsa hiçbir şey yapmaz, ve perleşleşmelerin bulunduğu satırların yerine geçebilir .

İkili dosyaları yoksaymak için Ianahtarını ekleyin grep. Harf duyarlı tutması için, açılan igeçişe grepve iikame ekspresyonuna bağlı bayrak, ancak değili üzerinde anahtar perlkendisi.


Perl'in kendisi bir dosya yapısını yineleyebiliyor. Aslında, find2perlPerl ile birlikte gelen, bu tür şeyleri xargshile yapmadan yapan bir araç var .
tripleee

@tripleee finddosya içeriğini aramaz ve asıl nokta sadece Perl programı yazmadan eşleşen dosyaları işlemektir .
Walf

Bu, sed tabanlı çözümlerin satır sonlarını dönüştürme sorununu önlediği için Windows için güzel bir çözümdür. Teşekkürler!
JamHandy

4

Genellikle grep ile değil, sed -i 's/string_to_find/another_string/g'veya ile perl -i.bak -pe 's/string_to_find/another_string/g'.


3

Git deposunda findve kullanırken çok dikkatli olun sed! İkili dosyaları hariç tutmazsanız, bu hatayla karşılaşabilirsiniz:

error: bad index file sha1 signature 
fatal: index file corrupt

Bu hatayı çözmek için Geri döndürmek için gereken sedŞu Verilerinizi değiştirerek new_stringinizle old_string. Bu, değiştirilen dizelerinizi geri alır, böylece sorunun başlangıcına dönersiniz.

Bir dizeyi aramanın ve değiştirmenin doğru yolu , ikili dosyaları yok saymak için atlamak findve kullanmaktır grep:

sed -ri -e "s/old_string/new_string/g" $(grep -Elr --binary-files=without-match "old_string" "/files_dir")

@Hobs için krediler


1

İşte yapacağım şey:

find /path/to/dir -type f -iname "*filename*" -print0 | xargs -0 sed -i '/searchstring/s/old/new/g'

bu filename, dosya adında bulunan tüm dosyaları bulur , bulunan /path/to/dirher dosyaya göre, ile satırı arayın searchstringve oldonunla değiştirin new.

Yine filenamede, dosyanın adında bir dize içeren belirli bir dosyayı aramayı atlamak istiyorsanız , yapmanız yeterlidir:

find /path/to/dir -type f -print0 | xargs -0 sed -i '/searchstring/s/old/new/g'

Bu yukarıdaki aynı şeyi yapar, ancak altında bulunan tüm dosyalara /path/to/dir.


0

Başka bir seçenek sadece perl'i globstar ile kullanmak olacaktır.

shopt -s globstarSizin .bashrc(veya her yerde) etkinleştirme , **glob deseninin tüm alt dizinleri ve dosyaları özyinelemeli olarak eşleştirmesini sağlar .

Böylece kullanarak perl -pXe 's/SEARCH/REPLACE/g' -i **ardışık yerini alacak SEARCHolan REPLACE.

-XO dizinleri şikayet etmeyeceğini hangi yollarla - bayrak "tüm uyarıları devre dışı" perl söyler.

Globstar ayrıca gibi şeyler yapmak için izin verir sed -i 's/SEARCH/REPLACE/g' **/*.extDeğiştirmeye isteseydi SEARCHile REPLACEuzantılı tüm alt dosyalarda .ext.


"Başka bir seçenek sadece globtar ile perl kullanmak olacaktır ..." - Solaris gibi Posixy makinelerinde değil. Bu yüzden özellikle arıyorum grepve sed.
jww
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.