Sed kullanarak ilk eşleşmeden sonra satır ekle


245

Bazı nedenlerden dolayı bunun basit bir cevabını bulamıyorum ve şu anda biraz zaman geçirdim. sedKomutu kullanarak belirli bir dizeyle eşleşen ilk satırdan sonra metnin seçim satırını eklemeyi nasıl başardım ? Sahibim ...

CLIENTSCRIPT="foo"
CLIENTFILE="bar"

Ve sonra gelen bir çizgi eklemek istiyorum CLIENTSCRIPT=sonuç ...

CLIENTSCRIPT="foo"
CLIENTSCRIPT2="hello"
CLIENTFILE="bar"

Yanıtlar:


379

GNU sed kullanarak bunu deneyin:

sed '/CLIENTSCRIPT="foo"/a CLIENTSCRIPT2="hello"' file

yerinde değiştirmek istiyorsanız ,

sed -i '/CLIENTSCRIPT="foo"/a CLIENTSCRIPT2="hello"' file

Çıktı

CLIENTSCRIPT="foo"
CLIENTSCRIPT2="hello"
CLIENTFILE="bar"

doktor


Teşekkürler! Ve dosyanın içeriğini yazdırmadan dosyaya geri yazmak için?
user2150250 21:13

11
Her ikisinin de GNU olduğunu varsayalım sed. Bu standart bir sedsözdizimi değildir ve diğer seduygulamalarla çalışmaz .
Stephane Chazelas

Farklı bir sınırlayıcı kullandığım için bunu benim için çalışmakta zorlandım. RTFM'den sonra, regex'i bir \, sonra da sınırlayıcı ile başlatmam gerektiğini fark ettim.
Christy

10
YALNIZCA ilk maça nasıl uygulanır? maçtan sonra metin eklediği açıktır, ancak sadece ilk maça nasıl bilebilir?
Mohammed Noureldin

7
Bu benim için her maçtan sonra metni ekler.
schoppenhauer

49

Standart sedsözdizimini not edin (POSIX'te olduğu gibi, sedçevresindeki tüm uyumlu uygulamalar tarafından desteklenir (GNU, OS / X, BSD, Solaris ...)):

sed '/CLIENTSCRIPT=/a\
CLIENTSCRIPT2="hello"' file

Veya bir satırda:

sed -e '/CLIENTSCRIPT=/a\' -e 'CLIENTSCRIPT2="hello"' file

( -expressions (ve -files içeriği ) sed script sedyorumlarını oluşturmak için yeni satırlarla birleştirilir ).

-iYerinde düzenleme için seçenek de destek (FreeBSD gibi) bir GNU oluşumudur, bazı diğer uygulamaları -i ''bunun için.

Alternatif olarak, taşınabilirlik için perlbunun yerine şunları kullanabilirsiniz :

perl -pi -e '$_ .= qq(CLIENTSCRIPT2="hello"\n) if /CLIENTSCRIPT=/' file

Yoksa kullanabilirsiniz edveya ex:

printf '%s\n' /CLIENTSCRIPT=/a 'CLIENTSCRIPT2="hello"' . w q | ex -s file

2
Yanlış olabilirim, ancak akım sed -e '/CLIENTSCRIPT=/a\' -e 'CLIENTSCRIPT2="hello"' fileilk parametrenin sonunda alıntıdan kaçar ve komutu kırar.
Terk Edilmiş Sepet

1
@AbandonedCart, Bourne cshveya rcailenin kabuklarında, '...'ters eğik çizginin özel olmadığı güçlü alıntılardır. Bildiğim tek istisna fishkabuk.
Stephane Chazelas

1
MacOS'taki terminal (ve daha sonra terminalde çalıştırılan bir komut dosyası) da bir istisnadır. Alternatif sözdizimi buldum, ama yine de teşekkürler.
Terk Edilmiş Sepet

1
@AbandonedCart, bu başka bir şey. sedBurada macOS POSIX uyumlu değil. Bu taşınabilir (yanlış olan bir satır varyant) hakkında benim açıklama yapar. Opengroup'tan gerçekten benim için standardın bir uygunsuzluğu veya yanlış yorumlanması olup olmadığını onaylamanızı isteyeceğim.
Stephane Chazelas

19

sKomutu kullanarak POSIX uyumlu olan :

sed '/CLIENTSCRIPT="foo"/s/.*/&\
CLIENTSCRIPT2="hello"/' file

1
... hatta yeni satırlar eklemeyi bile destekliyor. Onu seviyorum!
Stephan Henningsen

1
Ayrıca sed -e '/.../s/$/\' -e 'CLI.../'geçerli karakterler oluşturmayan bayt dizileri içeren satırlarla ilgili sorunlardan kaçınacak olanlara bakın .
Stephane Chazelas

14

MacOS (en azından OS 10) ve Unix için çalışan sed komutu (yani Gilles'in (şu anda kabul edilen) gibi gnu sed gerektirmez):

sed -e '/CLIENTSCRIPT="foo"/a\'$'\n''CLIENTSCRIPT2="hello"' file

Bu bash ve belki de $ '\ n' değerlendirme teklif stilini bilen diğer kabukları çalışır. Her şey bir satırda olabilir ve eski / POSIX sed komutlarında çalışabilir. CLIENTSCRIPT = "foo" (veya eşdeğeri) ile eşleşen birden fazla satır varsa ve yalnızca fazladan bir satırı ilk kez eklemek isterseniz, aşağıdaki gibi yeniden çalışabilirsiniz:

sed -e '/^ *CLIENTSCRIPT="foo"/b ins' -e b -e ':ins' -e 'a\'$'\n''CLIENTSCRIPT2="hello"' -e ': done' -e 'n;b done' file

(bu, satır ekleme kodundan sonra sadece dosyanın geri kalanında dolaşan ve bir daha asla ilk sed komutuna geri dönmeyen bir döngü oluşturur).

Satırın bir yorumda, diyelim veya girintili olması durumunda, eşleşen desene bir '^ *' eklediğimi fark edebilirsiniz. % 100 mükemmel değil, ancak yaygın olması muhtemel diğer durumları da kapsar. Gerektiği gibi ayarlayın ...

Bu iki çözüm aynı zamanda (genel çözüm için bir satır eklemeye yönelik), yeni eklenen satırınız çıkışsız ters eğik çizgiler veya "ve" işaretleri içeriyorsa, sed tarafından yorumlanacağı ve büyük olasılıkla olduğu gibi aynı şekilde çıkmayacakları sorununu çözer \n. \0eşleşen ilk satır olur. Özellikle önce {{var //} önce veya başka bir sed deyimi vb. Kullanarak her şeyden kaçmanız gereken bir değişkenden gelen bir satır ekliyorsanız kullanışlıdır.

Bu çözüm, komut dosyalarında biraz daha az dağınıktır (alıntı yapmak ve \ n olsa da okunması kolay değildir), bir komutun yerine konacak metni satırın başlangıcına, bir işlevde koymak istemediğinizde girintili çizgilerle. Ben $ '\ n' yeni satır için kabuk tarafından değerlendirilir, normal '\ n' tek tırnaklı değerlerde değil avantaj elde ettim.

Onun perl / hatta awk düşünüyorum daha okunabilir olması nedeniyle kazanabilirsiniz düşünüyorum yeterince uzun Başlarken.


1
Cevap için teşekkür ederim! Birincisi AIX OS'de de bir cazibe gibi çalışıyor.
abhishek

bunu çok satırlı ekleme için nasıl yapıyorsunuz?
tatsu

1
POSIX sed, bir ters eğik çizgi ( kaynak ) ile "kaçarsanız" değiştirme dizesindeki gerçek satırları destekler . Yani: s/CLIENTSCRIPT="foo"/&\ [Enter] CLIENTSCRIPT2="hello"/ . Ters eğik çizgi, bu yorumda nasıl göründüğünün aksine, satırdaki en son karakter olmalıdır (ondan sonra boşluk yok).
thedudeabides

1
@tatsu Değiştirme komut satırındaki satır satırlarının s///yanı sıra ave ikomutlarındaki satır satırları, yukarıdaki yorumumda açıkladığım aynı yöntem kullanılarak " kaçabilir ".
thedudeabides

4

Belki bunun cevabını vermek için biraz geç, ama yukarıdaki çözümlerden bazılarını biraz hantal buldum.

Sed basit dize değiştirme denedim ve çalıştı:

sed 's/CLIENTSCRIPT="foo"/&\nCLIENTSCRIPT2="hello"/' file

& işareti eşleşen dizeyi yansıtır ve ardından \ n ve yeni satırı eklersiniz.

Belirtildiği gibi, yerinde yapmak istiyorsanız:

sed -i 's/CLIENTSCRIPT="foo"/&\nCLIENTSCRIPT2="hello"/' file

Başka bir şey. Bir ifade kullanarak eşleşebilirsiniz:

sed -i 's/CLIENTSCRIPT=.*/&\nCLIENTSCRIPT2="hello"/' file

Umarım bu birine yardımcı olur


Bu, GNU sed'in varsayılan olduğu Linux'ta iyi çalışır, çünkü \ndeğiştirme dizesinde anlar . Düz-vanilya (POSIX) sedyok değil anlamaya \n, ancak, yedek dizede BSD veya MacOS-sürece GNU nasılsa sed yükledim bu kadar bu olmaz işi. Vanilya sed ile yapabilirsiniz bunları yani "kaçan" dir, ters eğik çizgi çizgi biten ardından basarak yeni satır gömmek [Enter] ( referans için başlığı altında [2addr]s/BRE/replacement/flags). Bu, sed komutunuzun terminalde birden çok satıra yayılması gerektiği anlamına gelir.
thedudeabides

Değiştirme dizesinde gerçek bir yeni satır almak için başka bir seçenek , diğer yanıtlardan birinde belirtildiği gibi Bash'teki ANSI-C alıntı özelliğini kullanmaktır .
thedudeabides


1

Benzer bir görevim vardı ve yukarıdaki perl çözümünü çalıştıramadım.

İşte benim çözümüm:

perl -i -pe "BEGIN{undef $/;} s/^\[mysqld\]$/[mysqld]\n\ncollation-server = utf8_unicode_ci\n/sgm" /etc/mysql/my.cnf

Açıklama:

/Etc/mysql/my.cnf dosyamda yalnızca içeren bir satırı aramak için normal bir ifade kullanır [mysqld]ve yerine

[mysqld] collation-server = utf8_unicode_ci

collation-server = utf8_unicode_ciiçeren satırdan sonra doğru satır ekleme [mysqld].


0

Bunu hem Mac hem de Linux işletim sistemleri için son zamanlarda da yapmak zorunda kaldım ve birçok gönderiye göz attıktan ve birçok şeyi denedikten sonra, özel görüşüme göre, istediğim yere hiç ulaşmadım: ve basit komutlara sahip standart komutlar, bir astar, taşınabilir, daha fazla kısıtlama eklemek için genişletilebilir. Sonra farklı bir bakış açısıyla bakmaya çalıştım, o zaman "2 astar" kriterlerimin geri kalanını karşıladığında "tek astar" seçeneği olmadan yapabileceğimi fark ettim. Sonunda ben herkesle paylaşmak istedim Ubuntu ve Mac hem de çalışır gibi bu çözüm ile geldi:

insertLine=$(( $(grep -n "foo" sample.txt | cut -f1 -d: | head -1) + 1 ))
sed -i -e "$insertLine"' i\'$'\n''bar'$'\n' sample.txt

İlk komutta grep, "foo" içeren satır numaralarını arar, kesme / kafa 1. tekrarı seçer ve tekrardan sonra eklemek istediğim için ilk tekrar satır numarasını 1 olan aritmetik op artışlarını arar. İkinci komutta, eklemek için yerinde bir dosya düzenleme, "i": ansi-c alıntı yeni satır, "bar", sonra başka bir yeni satır. Sonuç, "foo" satırından sonra "bar" içeren yeni bir satır eklemektir. Bu 2 komutun her biri daha karmaşık işlemlere ve eşleşmeye genişletilebilir.

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.