“Sed” yerinde yapılan değişiklikler nasıl bildirilir?


23

sedDizeleri yerinde değiştirmek için kullanırken , yaptığı değişiklikleri rapor etmesini sağlamanın bir yolu var mı (eski ve yeni dosyaların farkına güvenmeden)?

Örneğin, komut satırını nasıl değiştirebilirim

find . -type f | xargs sed -i 's/abc/def/g'

Böylece anında yapılan değişiklikleri görebiliyorum.

Yanıtlar:


15

Sen kullanabilirsiniz sed'ın wbiriyle bayrağı /dev/stderr, /dev/tty, /dev/fd/2sisteminizde destekleniyorsa. fileGibi bir giriş ile :

foo first
second: missing
third: foo
none here

çalışan

sed -i '/foo/{
s//bar/g
w /dev/stdout
}' file

çıktılar:

bar first
third: bar

gerçi fileiçeriğe değiştirildi:

bar first
second: missing
third: bar
none here

Yani senin durumunda, koşuyor:

find . -type f -printf '\n%p:\n' -exec sed -i '/foo/{
s//bar/g
w /dev/fd/2
}' {} \;

dosyaları yerinde ve çıktıda düzenler:

./file1:
bar malzemesi
daha fazla bar

./file2:

./file3:
önce bar
üçüncü: bar

Ayrıca, original line >>> modified lineörneğin:

find . -type f -printf '\n%p:\n' -exec sed -i '/foo/{
h
s//bar/g
H
x
s/\n/ >>> /
w /dev/fd/2
x
}' {} \;

dosyaları yerinde düzenler ve çıktılar:

./file1:
foo şeyler >>> bar malzemesi
daha fazla foo >>> daha fazla bar

./file2:

./file3:
ilk önce fo >>> bar ilk
üçüncü: foo >>> üçüncü: çubuk

16

pİlk seferde rint eylemini kullanarak iki seferde yapabilirsiniz:

find . -type f | xargs sed --quiet 's/abc/def/gp'

burada --quietyapar her satırı ve gösterme sed peki gösterir ikame eşleşen yalnızca hatları.

Bu, sed'nin hangi dosyaların değiştirildiğini göstermeyeceğini ve elbette ek bir karmaşıklıkla düzeltilebileceğini sınırlıyor.


İki geçişte ihtiyacın olduğundan istediğimi yapmıyor ama oy veriyorum çünkü bu şeyi öğrendim ve bu çok faydalı oldu. Özellikle dediğiniz gibi dosyalar da basıldıysa. Gibi bir şeyfor x in `find . -type f`; do echo ///File $x: ; sed --quiet 's/abc/def/gp' $x; done
ricab 23:13

@ msw Çok fazla ifadem var sed, /gpher biri için yazmak istemiyorum . Dünyayı nasıl kurarım?
alhelal

8

Bunun mümkün olduğunu sanmıyorum, ancak geçici çözüm bunun yerine perl kullanmak olabilir:

find . -type f | xargs perl -i -ne 's/abc/def/ && print STDERR' 

Bu değiştirilen çizgileri standart hataya basacaktır . Örneğin:

$ cat foo
fooabcbar
$ find . -type f | xargs perl -i -ne 's/abc/def/ && print STDERR' 
foodefbar

Bunu, satır numarasını, dosya adını, orijinal satırı ve değiştirilen satırı yazdırarak da biraz daha karmaşık hale getirebilirsiniz:

$ find . -type f | 
   xargs perl -i -ne '$was=$_; chomp($was);
                      s/abc/def/ && print STDERR "$ARGV($.): $was : $_"' 
./foo(1): fooabcbar : foodefbar

+1 Ayrıca $ARGV, çalıştırılmakta olan dosyanın adı için de kullanabilirsiniz .
Joseph R.

@JosephR. iyi nokta, eklendi.
terdon

Teşekkürler, bu muhtemelen yardımcı oldu (kendim test etmedim). Sed kullanmadığı için seçmiyorum, bu yüzden soruyu tam olarak yanıtlamıyor.
ricab

aslında sürece @ricab, iyi olduğunu, bir cevabı kabul etmemelidir cevap soru. Bunun gibi basit şeyler için, perlsözdiziminin 'lerinkine çok benzer olduğunu sedve ne istediğinizi aslında mümkün olduğunu sanmıyorum sed.
terdon

3

Geçerli deseni bir dosyaya yazan w bayrağı kullanılarak mümkündür . Bu yüzden ikame komutuna ekleyerek ardışık ikameleri bir dosyaya rapor edebilir ve iş bittikten sonra yazdırabiliriz. Ayrıca değiştirilen dizgiyi grep ile renklendirmeyi seviyorum.

sed -i -e "s/From/To/gw /tmp/sed.done" file_name
grep --color -e "To" /tmp/sed.done

W ve dosya adı arasında yalnızca bir boşluk olması gerektiğini unutmayın .

Bu, diff'den bile daha iyidir, çünkü diff, sed tarafından yapılmamış olsa bile değişiklikler gösterebilir.


Sadece test ettim ve sed sadece değiştirildiği satırları yazar sed.done. Orijinal dosyasında "To" ile çizgiler nedenle üzere basılmış değildir sed.donene zaman böylece grep "To" sed.doneyalnızca satırları göreceksiniz edilir değiştirilebilir sed. Orijinal çizgiyi değiştirilmeden önce dosyada göremezsiniz, hedeflediğiniz şey
buysa

1

@ Terdon çözümünü severim - perl bunun için iyidir.

İşte benim tweaked versiyonu:

  • eşleşen dizeye sahip olmayan dosyaları değiştirmeyi denemez
  • değişen dosyaların önceki sürümlerini yedekler (bir .bak sürümü oluşturun)
  • değiştirilen her dosya / linenoyu listeleyecek ve bu satırın ESKİ ve YENİ sürümlerini kolay okunması için girintili ve altta gösterecektir

kod

find /tmp/test -type f ! -name "*.bak" -exec grep -l '/opt/gridmon' {} \; | xargs -L1 perl -ni'.bak' -e'$old=$_; s/\/opt\/gridmon/~/g && print STDERR "$ARGV($.):\n\tOLD:$old\tNEW:$_"'

örnek çıktı

/tmp/test/test4.cfg(13):
    OLD:    ENVFILE /opt/gridmon/server/etc/gridmonserver.cfg
    NEW:    ENVFILE ~/server/etc/gridmonserver.cfg
/tmp/test/test4.cfg(24):
    OLD:    ENVFILE /opt/gridmon/server/etc/gridmonserver.cfg
    NEW:    ENVFILE ~/server/etc/gridmonserver.cfg
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.