Grep doğru satırı bulmak için, içeriği değiştirmek için sed, sonra orijinal dosyaya geri koymak?


9

Bir dosyadaki belirli bir satırda tek bir kelimeyi değiştirmeye çalışıyorum, ancak hep birlikte bağlanmakta sorun yaşıyorum.

Temel olarak, dosyamdaki bir satırda 'firmware_revision' anahtar kelimesi var ve bu satırda (ve sadece bu satırda) 'test' kelimesini 'üretim' kelimesiyle değiştirmek istiyorum.

Bunu yapabilirim:

grep 'firmware_revision' myfile.py | sed 's/test/production'

Bu, istediğim satırı seçecek ve yerine koymayı gerçekleştirecek, ancak eski satırı değiştirmek için bu yeni satırı orijinal dosyaya nasıl alacağımı anlayamıyorum. Açıkçası sadece dosyaya yönlendiremiyorum, ne yapmalıyım?

Tempoları kullansam bile, grepsadece ihtiyacım olan hattı almak için kullanarak dosyadaki diğer tüm verileri kaybettim, böylece artık sadece bir geçici dosyaya yönlendiremiyorum, sonra orijinali temp ile değiştiremiyorum.

Düzenle - Birisi daha fazla bilgi istedi

Diyelim ki böyle satırlarla dolu bir dosyam var

[
  ('key_name1', str, 'value1', 'Description'),
  ('key_name2', str, 'value2', 'Description'),
  ('key_name3', str, 'value3', 'Description'),
  ('firmware_revision', str, 'my-firmware-name-test', 'Firmware revision name')
]

şimdi 'firmware_revision' içeren satırı bulan ve 'line' kelimesinin tüm örneklerini 'üretim' olarak değiştiren bir komut dosyası (ideal olarak bir satır) yazmak istiyorum. 'Test' kelimesi o dosyanın başka yerlerinde olabilir ve bunların değiştirilmesini istemiyorum. Açık olmak gerekirse, yukarıdaki satırı şu şekilde değiştirmek istiyorum:

('firmware_revision', str, 'my-firmware-name-production', 'Firmware revision name')

Bunu nasıl yaparım?


5
sedçok güçlüdür, her iki işlevi de ( grepve yerine koymayı) gerçekleştirebilir, ancak hattın size nasıl yardımcı olduğu hakkında daha fazla bilgiye ihtiyacımız olacak.
grochmal

Orijinal mesaja daha fazla bilgi ekleyeceğim
John Allard

7
Deneyin:sed -i.bak '/firmware_revision/ s/test/production/' myfile.py
John1024

1
Ah mükemmel çalıştı! Sözdizimini açıklayabilir misiniz?
John Allard

@JohnAllard Çok iyi. Açıklama ile bir cevap ekledim.
John1024

Yanıtlar:


22

Deneyin:

sed -i.bak '/firmware_revision/ s/test/production/' myfile.py

Burada /firmware_revision/bir koşul olarak hareket eder. Normal ifade ile eşleşen satırlar için doğrudur firmware_revisionve diğer satırlar için yanlıştır. Koşul doğruysa, aşağıdaki komut yürütülür. Bu durumda, bu komut ilk geçtiği yerine bir yedek komutu testile production.

Başka bir deyişle, komut s/test/production/yalnızca normal ifadeyle eşleşen satırlarda yürütülür firmware_revision. Diğer tüm çizgiler değişmeden geçer.

Varsayılan olarak sed, çıktısını standart çıkışa gönderir. Ancak dosyayı yerinde değiştirmek istediniz. Bu yüzden -iseçeneği ekledik . Özellikle, -i.bakbir .bakuzantıyla kaydedilmiş bir yedek kopya ile dosyanın değiştirilmesine neden olur .

Komutun sizin için çalışmasına karar verdiyseniz ve tehlikeli bir şekilde yaşamak ve bir yedek oluşturmak istemiyorsanız, GNU sed (Linux) ile şunları kullanın:

sed -i '/firmware_revision/ s/test/production/' myfile.py

Aksine, BSD'de (OSX), -iseçeneğin bir argümanı olmalıdır. Yedek tutmak istemiyorsanız, boş bir argüman sağlayın. Böylece, kullanın:

sed -i '' '/firmware_revision/ s/test/production/' myfile.py

Düzenle

Sorusuna düzenlemek, OP sorar her oluşumu testhattı ile değiştirilmesi üzerine production. Bu durumda, global (o satır için) değiştirme için gsubstitute komutuna seçenek ekleriz :

sed -i.bak '/firmware_revision/ s/test/production/g' myfile.py

5
Bütünlük için, -i.bakparçayı da açıklamak isteyebilirsiniz .
Stephen Harris

5
@StephenHarris İyi bir nokta. Ekleme açıklaması -i.
John1024

Muhtemelen yıldızlara ulaşabileceğinizi hissediyorum, sadece kitapta duran ve sedyapabileceğiniz her şeyi açıklayın ...
KlaymenDK

Değil BSD insan için John1024 @, ilk nedenlerini ekleyebilirsiniz ''sonrasÖ -i?
Hastur

3
OP bu satırdaki 'test' kelimesinin tüm örneklerini 'üretim' olarak değiştirmek istedi . Bu durumda sed komutuna / g öğesini eklemek önemlidir: sed -i '/firmware_revision/ s/test/production/g' myfile.pyaksi takdirde yalnızca ilk örnek değiştirilir.
knub

4

sedSeçeneği desteklemeyen eski okulu olan eski makinelerde -i:

TF=$( mktemp -t "${0##*/}"_$$_XXXXXXXX ) && \
trap 'rm -f "$TF"' EXIT HUP INT QUIT TERM && \
sed '/firmware_revision/ s/test/production/' myfile.py >"$TF" && \
mv -f "$TF" myfile.py

1
Bu eski makinelerde sadece edbir satırda kullanabilir ve yapabilirsiniz:printf %s\\n g/firmware_revision/s/test/production/g w q | ed -s myfile.py
don_crissti

1
@don_crissti Çok doğru, ama ed(1)kullanımını göstermek için herhangi bir bahane sunmuyor mktemp(1).
Satō Katsura

Geçici dosya kullanıyorsanız, orijinal dosyanın inode ve izinlerini de olduğu gibi koruyabilirsiniz ed. Bunun yerine mv -f "$TF" myfile.plkullanın cat "$TF" > myfile.pl && rm -f "$TF". BTW, küçük harfli değişken adları kullanmak $tfyerine iyi bir uygulamadır, bunun yerine $TFherhangi bir bash yerleşik değişkeniyle (muhtemelen diğer bourne kabukları ile) çatışmamaları garanti edilir.
cas

@cas Re:: şunu cat "$TF" > myfile.pldeneyin: touch a b; chmod 0444 a; cat b >a(BTW, sed -ibu durumda da çalışmaz). Kullanıcının bununla başa çıkmasına izin verseniz iyi olur. Re:: rm -f "$TF"gerekli değil, bkz trap ... EXIT. Re: $tfyerine $TF: belki; bu bir stil meselesi.
Satō Katsura

Bu, unix dosya izinlerinin normal ve beklenen davranışıdır. Demek istediğim, yeni bir dosya oluşturmak ve orijinalin üzerine göndermek 1. bu dosya adı için yeni bir inode ile sonuçlanacak (sabit bağlantıları kırarak). 2. akım umask orijinal izinlerden farklıysa muhtemelen izinleri değiştirin . Büyük harf çeşitlerine gelince, bu sadece bir stil meselesi değildir - büyük harf PATH veya RANDOM veya SHELL kullanma hatası yapan birçok kişi veya kendi değişkenleri için her şeyi zor yoldan öğrendi. (ve evet, sıklıkla kendim büyük harf kullanıyorum. Yanlış olduğunu biliyorum, alışkanlığı kırmaya çalışıyorum).
cas
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.