Sed ve grep / egrep kullanarak arama ve değiştirme


97

Onu egrep -Ryaklaşık 10 sendika içeren bir düzenli ifade kullanıyorum , örneğin: .jpg | .png | .gifvb. Bu iyi çalışıyor, şimdi bulunan tüm dizeleri ile değiştirmek istiyorum.bmp

Gibi bir şey düşünüyordum

egrep -lR "\.jpg|\.png|\.gif" . | sed "s/some_expression/.jpg/" file_it_came_form

bu yüzden buradaki mesele, benzer bir birleşim düzenli ifadesini içinde sednasıl yapacağım ve değişiklikleri girdiyi aldığı dosyaya kaydetmesini nasıl söyleyeceğim.


2
Bu soruyu, bir dizin hiyerarşisindeki birden çok dosyada arama ve değiştirme yollarını ararken buldum. Benim durumumdaki diğerleri için rpl'yi deneyin .
titaniumdecoy

teşekkür ederim rpl çalışıyor ve hatırlaması gerçekten çok kolay .. sadece rpl old_string new_string target_files.
cesarpachon

Yanıtlar:


183

Bu komutu kullanın:

egrep -lRZ "\.jpg|\.png|\.gif" . \
    | xargs -0 -l sed -i -e 's/\.jpg\|\.gif\|\.png/.bmp/g'
  • egrep: genişletilmiş normal ifadeler kullanarak eşleşen satırları bul

    • -l: yalnızca eşleşen dosya adlarını listele

    • -R: verilen tüm dizinlerde yinelemeli olarak arama

    • -Z: \0kayıt ayırıcı olarak kullan

    • "\.jpg|\.png|\.gif": Dizelerinden biri eşleşmelidir ".jpg", ".gif"ya".png"

    • .: aramayı geçerli dizinde başlat

  • xargs: bağımsız değişken olarak stdin ile bir komut çalıştır

    • -0: \0kayıt ayırıcı olarak kullanın . Bu eşleştirmek önemlidir -Zarasında egrepve giriş dosya isimleri boşluk ve satırbaşıyla aptal önlemek için.

    • -l: parametre olarak komut başına bir satır kullanın

  • sed: S Team, ed in-

    • -i: girdi dosyasını yedeklemeden çıktıyla değiştirin

    • -e: aşağıdaki bağımsız değişkeni ifade olarak kullanın

    • 's/\.jpg\|\.gif\|\.png/.bmp/g': Dizeleri tüm tekrarlarını değiştirmek ".jpg", ".gif"ya da ".png"birlikte".bmp"


hariç hepsi çalışır | sed kısmında. Mantıklı olduğu için neden anlamıyorum ... xargs'ın -l kısmı bana hatalar veriyordu, bu yüzden onu çıkardım, bu ilgili olabilir mi?
Ori

Bu komutun işlediği tüm dosyaların sonuna bir satırsonu eklediğini buldum.
titaniumdecoy

@titanumdecoy: Bu davranışı yeniden oluşturamadım. hangi sed sürümünü kullanıyordunuz ve hangi işletim sistemindesiniz?
David Schmitt

1
@DavidSchmitt: Muhtemelen sed -rgenişletilmiş düzenli ifadeler için kullanmak istiyorsunuz . Bu noktada, kalıp egrep'te kullanılanla eşleşecektir ve yeniden kullanım için bir değişkene koymak isteyebilirsiniz.
bukzor

bu komut, yaptığım kitaplık için başlık dosyalarını uygulamamın dışına kopyalamakla saatlerimi kurtardı. Bu harika :) İşte egrep -lRZ "\ .h $" kullandığım komut. | xargs -0 tar -cvf headers.tar | (cp headers.tar başlıkları; cd başlıkları; tar xf başlıkları.tar;)
The Lazy Coder

11

Dürüst olmak gerekirse, uygun görevler için sed'i sevdiğim kadar, bu kesinlikle perl için bir görev - bu tür tek satırlılar için, özellikle "geldiği yere geri yazmak" için gerçekten daha güçlü (perl'in -ianahtarı bunu ve isteğe bağlı olarak eski sürümü, örneğin bir .bak eklenmiş olarak saklamanıza izin verir -i.bak;

perl -i.bak -pe 's/\.jpg|\.png|\.gif/.jpg/

sed (mümkün olsa bile) veya awk gibi karmaşık çalışmak yerine ...


6
sed -i kullanır, tıpkı perl gibi.
Stobor

@Stobor - Yemin ederim, regex değiştirme dizesini beslediğimde perl işleminin tam olarak istediğimi yaptığı sorunları yaşadım, sed'in aksine, normal ifade seçeneğini vermiş olsam bile sed.. Sanırım ya sed için bazı bayrakları unuttum ya da sınırlamaları vardı.
meder omuraliev

10

Bunu yapmanın başka bir yolu

find . -name *.xml -exec sed -i "s/4.6.0-SNAPSHOT/5.0.0-SNAPSHOT/" {} \;

Yukarıdaki komutla ilgili biraz yardım

Bulma, ile gösterilen mevcut dizinde sizin için bulacaktır. .

-name benim durumumda dosyanın adı, pom.xml joker karakterleri verebilir.

-exec yürütmek

sed akış düzenleyici

-i durumu görmezden gel

s ikame için

/4.6.0.../ Aranacak dize

/5.0.0.../ Değiştirilecek dize


belki o kadar güçlü değil - ama bunu anlamak benim için kabul edilen cevaptan çok daha kolay
icc97

5

Bu sayfadaki komutlardan hiçbirinin benim için çalışmasını sağlayamadım: sed çözümü , işlediği tüm dosyaların sonuna bir satırsonu ekledi ve perl çözümü , find'dan yeterli argüman kabul edemedi. Mükemmel çalışan bu çözümü buldum:

find . -type f -name '*.[hm]' -print0 
    | xargs -0 perl -pi -e 's/search_regex/replacement_string/g'

Bu akım dizin ağacı recurse ve yerini alacak search_regexolan replacement_stringherhangi dosyalarda biten .hya .m.

Geçmişte de bu amaçla rpl kullandım .


0

for döngüsü kullanarak bir şeyler dene

 for i in `egrep -lR "YOURSEARCH" .` ; do echo  $i; sed 's/f/k/' <$i >/tmp/`basename $i`; mv /tmp/`basename $i` $i; done

hoş değil ama yapmalı.


3
xargs burada kesinlikle daha uygundur.
Nathan Fellman

1
ve |while read ikalıbı kullanmak, egrep'in sonuçları çok uzun olduğunda akışa olanak tanıyacak ve uzunluk kısıtlamalarını engelleyecektir
David Schmitt

0

Benim kullanım durumu ben değiştirmek istediğini oldu foo:/Drive_Letterile foo:/bar/baz/xyz Benim durumumda Aşağıdaki kod ile bunu başardı. Dosyaların çok büyük olduğu aynı dizin konumundaydım.

find . -name "*.library" -print0 | xargs -0 sed -i '' -e 's/foo:\/Drive_Letter:/foo:\/bar\/baz\/xyz/g'

umarım yardımcı olmuştur.

GÜNCELLEME s | foo: / Drive_letter: | foo: / ba / baz / xyz | g


Sed komutu için diğer sınırlayıcıları kullanabilirsiniz ve bunu yapmak yol adlarını çok daha güzel hale getirir:sed 's|foo:/Drive_letter:|foo:/ba/baz/xyz|g'
Kevin
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.