Sh komut dosyasında sed kullanırken kaçmak için hangi karakterlere ihtiyacım var?


248

Aşağıdaki betiği alın:

#!/bin/sh
sed 's/(127\.0\.1\.1)\s/\1/' [some file]

Bunu sh( dashburada) çalıştırmayı denersem, kaçması gereken parantezler nedeniyle başarısız olur. Ama yok (sekizli arasındaki veya tersbölülerle kendilerini kaçmak gerekir \sya \1). Buradaki kural nedir? Ne zaman ihtiyacım olacak {...}veya [...]? Yaptıklarımın ve kaçmaya gerek olmadıklarımın bir listesi var mı?


1
İşte SED ile kullanım için yolları dönüştürmek için bir bash işlevi:function sedPath { path=$((echo $1|sed -r 's/([\$\.\*\/\[\\^])/\\\1/g'|sed 's/[]]/\[]]/g')>&1) } #Escape path for use with sed
user2428118


Dura lex, sed sed
Nemo

Yanıtlar:


281

Burada iki yorumlama seviyesi vardır: kabuk ve sed.

Kabukta, tek tırnaklar arasındaki her şey, tek tırnak işaretleri dışında, kelimenin tam anlamıyla yorumlanır. Yazılarla tek tırnaklar arasında tek bir alıntıyı etkin bir şekilde kullanabilirsiniz '\''(tek teklifi kapat, tek harfli tek teklifi, tek teklifi aç).

Sed, temel düzenli ifadeleri kullanır . Bir BRE'de, kelimenin tam anlamıyla $.*[\^işlem görmeleri için, karakterlerin iç karakter kümeleri ( […]) hariç, bunlardan önce bir ters eğik çizgi ile alıntılanması gerekir . Harfler, rakamlar ve (){}+?|alıntı yapılmamalıdır (bazı uygulamalarda bunlardan bazılarını alıntı yaparak kaçabilirsiniz). Sekansları \(, \), \nve bazı uygulamalarda \{, \}, \+, \?, \|ve diğer eğik çizgi + alfasayısal özel anlamları vardır. $^Bazı uygulamalarda bazı pozisyonlarda alıntı yapmaktan kaçınabilirsiniz .

Ayrıca, /parantez ifadelerinin dışındaki regex'te görünmek için önce bir ters eğik çizgi gerekir . Bunu yazılı tarafından ayırıcı olarak alternatif bir karakter seçebilir, örneğin s~/dir~/replacement~ya \~/dir~p; BRE'ye eklemek istiyorsanız, sınırlayıcıdan önce bir ters eğik çizgiye ihtiyacınız olacaktır. Bir BRE'de özel bir anlamı olan bir karakter seçtiyseniz ve kelimenin tam anlamıyla eklemek istiyorsanız, üç ters eğik çizgi gerekir; Bazı uygulamalarda farklı davranabileceğinden, bunu önermiyorum.

Özetle, için sed 's/…/…/':

  • Regex'i tek tırnak arasında yazın.
  • '\''Regex'te tek bir alıntı yapmak için kullanın .
  • $.*/[\]^Sadece bu karakterlerden önce ve sonra ters eğik çizgi koyun (ancak parantez ifadelerinin içinde değil). (Teknik olarak daha önce ters eğik çizgi koymamalısınız, ]ancak parantez ifadelerinin dışında ]ve \]farklı şekilde işleyen bir uygulama bilmiyorum .)
  • Bir parantez ifadesinin içinde, -kelimenin tam anlamıyla ele alınmak üzere ilk veya son ( [abc-]veya [-abc]değil [a-bc]) olduğundan emin olun .
  • İçin parantez ifadelerinde içinde, ^kelimenin tam anlamıyla tedavi edilmesi, emin yapmak değil (kullanım ilk [abc^]değil [^abc]).
  • Dahil etmek için ]bir braket ifadesinin eşleştiği karakterlerin listesinde, bu (veya ilk sonraki ilk karakteri yapmak ^bir reddedildiği seti için): []abc]ya [^]abc](değil [abc]]ne de[abc\]] ).

Yeni metinde:

  • &ve \sınırlayıcı (genellikle /) ve newlines gibi, onlardan önce bir ters eğik çizgi ile alıntı yapılmalıdır .
  • \ardından bir rakamın özel bir anlamı vardır. \ardından bir harfin bazı uygulamalarda özel bir anlamı (özel karakterler) vardır ve \ardından diğer bazı karakter araçları \cveya cuygulamaya göre değişir.
  • Bağımsız değişken ( sed 's/…/…/') etrafındaki tek tırnak işaretleri ile '\''değiştirme metnine tek bir teklif koymak için kullanın .

Düzenli ifade veya değiştirme metni bir kabuk değişkeninden geliyorsa, bunu unutmayın.

  • Düzenli ifade bir BRE'dir, değişmez bir dizedir.
  • Düzenli ifadede, bir yeni satırın \n( seddesen alanına yeni satır karakterleri ekleyen başka bir kodunuz olmadığı sürece asla eşleşmeyecek) olarak ifade edilmesi gerekir . Ancak, bazı seduygulamalarla birlikte parantez ifadelerinde işe yaramayacağını unutmayın .
  • Yedek Metinde, &, \ve satırbaşları alıntı gerekmektedir.
  • Sınırlayıcının alıntılanması gerekir (ancak parantez ifadelerinin içinde değil).
  • Enterpolasyon için çift tırnak kullanın: sed -e "s/$BRE/$REPL/".

Gerçek joker karakterden (*) kaçmak, çift ters eğik çizgi ( \\*) kullanabilirsiniz. Örnek:echo "***NEW***" | sed /\\*\\*\\*NEW\\*\\*\\*/s/^/#/
danger89

43

Karşılaştığınız sorun enterpolasyon ve sızıntılardan ibaret değildir - bunun nedeni, -rveya --regexp-extendedseçeneğini değiştirmeden genişletilmiş düzenli ifade sözdizimini kullanmaya çalıştığınızdır .

Sed çizginizi şuradan değiştirin:

sed 's/(127\.0\.1\.1)\s/\1/' [some file]

için

sed -r 's/(127\.0\.1\.1)\s/\1/' [some file]

ve niyetine inandığım gibi işe yarayacak.

Sed, varsayılan olarak, aşağıdaki sözdizimini gerektiren temel düzenli ifadeleri kullanır (grep stilini düşünür):

sed 's/\(127\.0\.1\.1\)[ \t]/\1/' [some file]

Yine bu problemi yaşadım ve en son aldığım çözümü bulmak için aşağı kaydırmayı unuttum. Tekrar teşekkürler.
isaaclw

Çok teşekkürler. -rBir seçenek olarak eklemek benim için gerekli olan şeydi.
HelloGoodbye

15

Bir kabuk değişkenini sed ifadesine enterpolasyon yapmak istemiyorsanız, tüm ifade için tek tırnak işaretleri kullanın, çünkü bunlar arasındaki her şeyin ters eğik çizgiler de dahil olmak üzere olduğu gibi yorumlanmasına neden olurlar.

Yani eğer görmek s/\(127\.0\.1\.1\)\s/\1/için sed'in etrafına tek tırnaklar koyarsanız ve kabuk içindeki parantezlere veya ters eğik çizgilere dokunmaz. Bir kabuk değişkenini enterpolasyona sokmanız gerekirse, yalnızca bu bölümü çift tırnak içine alın. Örneğin

sed 's/\(127\.0\.1\.1\)/'"$ip"'/'

Bu, hangi kabuk meta karakterlerinin çift tırnak işaretleri ile kaçılmadıklarını hatırlamakta zorluk çeker.


sedGörmek istiyorum s/(127\.0\.1\.1)/..., ancak bunu bir kabuk betiğine olduğu gibi koymak işe yaramıyor. Kabuk hakkında söyledikleriniz parantezlere dokunmama yanlış görünüyor. Çalışmak için sorumu değiştirdim.
saat

3
Kabuk parantezlere dokunmuyor. Sırt sırta ihtiyacın var çünkü sed onları görmeye ihtiyaç duyuyor. sed 's/(127\.0\.1\.1)/IP \1/'sed görmesi gerekiyor çünkü başarısız \(ve \)grup sözdizimi, değil (ve ).
Kyle Jones

facepalm Adam sayfasında değil, bulduğum çevrimiçi bir el kitabında. Bu regex için normal midir, çünkü onu regex kütüphanelerinde kullanmak zorunda kalmamıştım (örneğin, Python gibi)?
saat

3
Geleneksel Unix komutları için, temel düzenli ifadeler ve genişletilmiş düzenli ifadeler vardır. Ayrıntılar . sed, temel normal ifadeleri kullanır, bu nedenle grup sözdizimi için ters eğik çizgi gerekir. Perl ve Python genişletilmiş düzenli ifadelerin ötesine geçti. Etrafımda dolaşırken, "düzenli ifade" derken sersemletirdiğimiz ne kafa karıştırıcı bir kabarcığı gösteren son derece bilgilendirici bir grafik buldum .
Kyle Jones

1
Ayrıca, tek tırnak içinde kullanılamayan tek karakterin tek bir alıntı olduğunu da eklerdim.
enzotib
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.