GNU veya BSD Sed'de regex değişimi / veya operatörü (foo | bar)


28

Çalışmasını sağlayamıyorum. GNU sed belgeleri borudan kaçmayı söylüyor, ancak bu işe yaramıyor, kaçmadan da düz bir boru kullanmıyor. Parens eklemek farketmez.

$ echo 'cat
dog
pear
banana
cat
dog' | sed 's/cat|dog/Bear/g'
cat
dog
pear
banana
cat
dog

$ echo 'cat
dog
pear
banana
cat
dog' | sed 's/cat\|dog/Bear/g'
cat
dog
pear
banana
cat
dog

Yanıtlar:


33

Varsayılan olaraksed kullandığı POSIX Temel Düzenli İfadeler içermez, |münavebe operatörü. Birçok versiyonları sedGNU ve FreeBSD, içine destek anahtarlama dahil Extended Normal İfadeler yapmak içerir |münavebeye. Bunu nasıl değiştirirsiniz: GNU sed kullanır-r , FreeBSD , NetBSD , OpenBSD ve OS X sed kullanır -E. Diğer sürümler çoğunlukla onu desteklemiyor. Kullanabilirsiniz:

echo 'cat dog pear banana cat dog' | sed -E -e 's/cat|dog/Bear/g'

ve bu BSD sistemlerinde ve GNU’da çalışacaktır sed -r.


GNU sedtamamen belgelenmemiş ancak çalışma desteğine sahip görünüyor -E, bu yüzden yukarıdakilerle sınırlı bir çoklu platform komut dosyası kullanıyorsanız, bu en iyi seçeneğinizdir. Belgelenmemiş olduğundan, muhtemelen buna gerçekten güvenemezsiniz.

Yorum, BSD sürümlerinin -rde belgelenmemiş takma adı olarak desteklediğini belirtiyor . OS X bugün hala mevcut değil ve daha eski NetBSD ve OpenBSD makinelerine erişemiyorum, ancak NetBSD 6.1'e de sahip. Evrensel olarak ulaşabileceğim ticari birlikler yok. Yani bütün bunlarla taşınabilirliği soru oldukça bu noktada karmaşık, ancak basit bir cevabı olduğunu oluyor geçmekawk her yerde Eres kullanan, bunu gerekirse.


Hepsinden bahsettiğiniz üç BSD , bu -rseçeneği -EGNU sed ile uyumluluk için eşanlamlı olarak destekliyor . OpenBSD'ler ve OS sed -EX'ler, çıkış borusunu alternatif operatör olarak değil, değişmez bir boru olarak yorumlayacaktır. İşte NetBSD man sayfasına çalışan bir link ve işte on yaşında olmayan OpenBSD için bir link .
damien



9

Bunun nedeni (a|b), Temel Düzenli İfade değil genişletilmiş bir düzenli ifade olmasıdır. Bununla -Ebaşa çıkmak için seçeneği kullanın .

echo 'cat
dog
pear
banana
cat
dog'|sed -E 's/cat|dog/Bear/g'

Gönderen sedadam sayfası:

 -E      Interpret regular expressions as extended (modern) regular
         expressions rather than basic regular expressions (BRE's).

Not -raynı şey için başka bayrak, ancak -Edaha taşınabilir ve hatta POSIX özellikleri sonraki sürümde olur.


6

Bunu yapmanın taşınabilir yolu - ve daha verimli yolu - adreslerle. Bunu yapabilirsiniz:

printf %s\\n cat dog pear banana cat dog |
sed -e '/cat/!{/dog/!b' -e '};cBear'

Bu şekilde, satır kedi dizesini içermiyorsa ve kodun dışına yayılmış köpek dizesini sed biçermiyorsa, geçerli satırına otomatik olarak basar ve bir sonraki çevrime başlamak için bir sonrakine geçer. Bu nedenle bir sonraki talimatı yerine getirmez - bu örnekte ctüm satırı Ayı'yı okumak için sarkar, ancak bir şey yapabilir.

Ayrıca belirterek muhtemelen değer olduğunu aşağıdaki herhangi deyim !bki sedkomuta edebilirsiniz yalnızca dize ya içeren bir satırda maç dogveya cat- Şimdi kurallarını uygulamak anlamına gelir - Eğer değil bir çizgi eşleşen herhangi bir tehlike olmaksızın başka testler böylece Sadece birisine veya diğerine.

Ama sıradaki o. İşte yukarıdaki komuttan çıktı:

###OUTPUT###
Bear
Bear
pear
banana
Bear
Bear

Ayrıca geri referansları olan arama tablosunu taşınabilir bir şekilde uygulayabilirsiniz.

printf %s\\n cat dog pear banana cat dog |
sed '1{x;s/^/ cat dog /;x
};G;s/^\(.*\)\n.* \1 .*/Bear/;P;d'

Bu basit örnek durum için kurulum yapmak çok daha fazla iş, ancak seduzun vadede daha esnek komut dosyaları oluşturabilir.

İlk satır I e de xdize insert sonra değişiklik tutma alanı ve desen alanı <space>kedi <space>köpek<space> e öncesinde tutma uzaya xgeri değişiyor.

O andan itibaren ve sonraki her satırda Gdesen uzayına eklenen bir boşluk tutuyorum, sonra satırın başından sonuna kadar eklediğim yeni satırın sonuna kadar tüm karakterlerin ondan sonra boşluklarla çevrili bir dizeyle eşleşip eşleşmediğini kontrol edin. Öyleyse, tüm partiyi Bear ile değiştiririm ve eğer zarar görmemişsem, çünkü Psadece desen uzayındaki ilk ortaya çıkan yeni dçizgiyi işaretlerim, sonra hepsini seçerim.

###OUTPUT###
Bear
Bear
pear
banana
Bear
Bear

Ve esnek derken, onu kastediyorum. Burada yerini aldığı kediyi ile brownbear ve köpek ile Blackbear :

printf %s\\n cat dog pear banana cat dog |
sed '1{x;s/^/ 1cat Brown 2dog Black /;x
};G;s/^\(.*\)\n.* [0-9]\1 \([^ ]*\) .*/\2Bear/;P;d'

###OUTPUT###
BrownBear
BlackBear
pear
banana
BrownBear
BlackBear

Tabii ki, arama tablosunun içeriğini büyük ölçüde genişletebilirsiniz - 90'lı yıllarda, tek bir açıklamadan nasıl kaba bir hesap makinesi oluşturduğunu anlattığında konuyu Greg Ubben'in usenet e-postalarından aldım sed s///.


1
phew, +1. Söylemem gereken kutuyu düşünmek için bir
hevesiniz var

@ 1_CR - Son düzenlememe bakın - fikrim değil - ki bundan hoşlanmadığımı ve bir iltifat olarak değerlendirdiğimi söyleyemem. Ama gerektiği yerde kredi vermeyi seviyorum.
mikeserv

1

Bu oldukça eski bir sorudur, ancak birinin denemek istemesi durumunda, bunu sed dosyalarında kullanmak için oldukça düşük bir çaba vardır. Her seçenek ayrı bir satırda listelenebilir ve sed her birini değerlendirir. Bu mantıklı bir eşdeğerdir veya. Örneğin, belirli bir kod içeren satırları kaldırmak için:

söyleyebilirsin : sed -E '/^\/\*!(40103|40101|40111).*\/;$/d'

veya bunu sed dosyanıza koyun:

/^\/\*!40103.*\/;$/d
/^\/\*!40101.*\/;$/d
/^\/\*!40111.*\/;$/d

0

İşte, uygulamaya özel seçeneklerden sed(örneğin -E, -r) faydalanmayan bir teknik . Deseni tek bir regex olarak tanımlamak yerine, cat|dogyalnızca sediki kez çalıştırabiliriz :

echo 'cat
dog
pear
banana
cat
dog' | sed 's/cat/Bear/g' | sed 's/dog/Bear/g'

Gerçekten bariz bir geçici çözüm, ancak paylaşmaya değer. Çok uzun bir zincir sedçok iyi görünmese de , doğal olarak ikiden fazla desen dizgisine genellenir .

Genellikle sed -idosyalarda değişiklik yapmak için (tüm uygulamalarda aynı şekilde çalışır) kullanırım. Burada, her geçici sonuç dosyaya kaydedildiğinden, uzun bir desen dizeleri listesi güzel bir şekilde dahil edilebilir:

for pattern in cat dog owl; do
    sed -i "s/${pattern}/Bear/g" myfile
done
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.