Komut satırından normal ifade ters eğik çizgisinden kaçmak için gereken ters eğik çizgi sayısı


12

Son zamanlarda komut satırında regex ile ilgili sorun yaşadım ve bir ters eğik çizgi eşleştirmek için farklı sayıda karakter kullanılabileceğini buldum. Bu sayı normal ifade için kullanılan kota bağlıdır (yok, tek tırnak, çift tırnak). Ne demek istediğim için aşağıdaki bash oturumuna bakın:

echo "#ab\\cd" > file
grep -E ab\cd file
grep -E ab\\cd file
grep -E ab\\\cd file
grep -E ab\\\\cd file
#ab\cd
grep -E ab\\\\\cd file
#ab\cd
grep -E ab\\\\\\cd file
#ab\cd
grep -E ab\\\\\\\cd file
#ab\cd
grep -E ab\\\\\\\\cd file
grep -E "ab\cd" file
grep -E "ab\\cd" file
grep -E "ab\\\cd" file
#ab\cd
grep -E "ab\\\\cd" file
#ab\cd
grep -E "ab\\\\\cd" file
#ab\cd
grep -E "ab\\\\\\cd" file
#ab\cd
grep -E "ab\\\\\\\cd" file
grep -E 'ab\cd' file
grep -E 'ab\\cd' file
#ab\cd
grep -E 'ab\\\cd' file
#ab\cd
grep -E 'ab\\\\cd' file

Bu şu demek:

  • tırnak işaretleri olmadan, bir ters eğik çizgiyi 4-7 gerçek ters eğik çizgi ile eşleştirebilirim
  • çift ​​tırnak ile, bir ters eğik çizgiyi 3-6 gerçek ters eğik çizgi ile eşleştirebilirim
  • Tek tırnak işaretleri ile, bir ters eğik çizgiyi 2-3 gerçek ters eğik çizgi ile eşleştirebilirim

Ekstra ters eğik çizgi, kabuk tarafından (bash man sayfasından) göz ardı edildiğini anlıyorum:

"Tırnaksız ters eğik çizgi (\) çıkış karakteridir. Sonraki karakterin gerçek değerini korur."

Bu tek tırnaklı örnekler için geçerli değildir, çünkü tek tırnak içinde kaçış yapılmaz.

Ve ek bir ters eğik çizgi grep komutu tarafından yok sayılır ("\ c" sadece "c" kaçar, ancak bu "c" ile aynıdır, çünkü "c" ifadesinin özel bir anlamı yoktur).

Bu, tek tırnaklı örneğin davranışını açıklar, ancak diğer iki örneği gerçekten anlamıyorum, özellikle neden alıntılanmamış çift tırnaklı dizeler arasında bir fark var.

Yine, bash man sayfasından bir alıntı:

Msgstr "Karakterleri çift tırnak içine almak $,`, \ ve tarih genişletmesi etkinleştirildiğinde! Hariç, tırnak içindeki tüm karakterlerin gerçek değerini korur. "

Aynısını GNU awk (örn. awk /ab\cd/{print} file) İle denedim, aynı sonuçlarla.

Bununla birlikte Perl farklı sonuçlar gösterir (örn. Kullanarak perl -ne "/ab\\cd/"\&\&print file):

  • tırnak işaretleri olmadan, bir ters eğik çizgiyi 4-5 gerçek ters eğik çizgi ile eşleştirebilirim
  • çift ​​tırnak ile, bir ters eğik çizgiyi 3-4 gerçek ters eğik çizgi ile eşleştirebilirim
  • Tek tırnak işaretleri ile bir ters eğik çizgiyi 2 gerçek ters eğik çizgi ile eşleştirebilirim

Herkes grep ve awk için komut satırında alıntılanmamış ve çift sıralı normal ifade dizeleri arasındaki farkı açıklayabilir mi? Perl'in davranışının bir açıklamasıyla ilgilenmiyorum, çünkü genellikle Perl tek gömleklerini kullanmıyorum.

Yanıtlar:


10

Alıntılanmamış örnek için, her bir \\çift ​​grep'e bir ters eğik çizgi geçirir, bu nedenle 4 ters eğik çizgi grep'e iki geçer, bu da tek bir ters eğik çizgiye dönüşür. 6 ters eğik çizgi üç tanesini grep'e geçirir, bir ters eğik çizgiye ve bir \ceşittir c. Ek bir ters eğik çizgi hiçbir şeyi değiştirmez, çünkü kabuk tarafından çevrilir \c-> c. Kabuktaki sekiz ters eğik çizgi grep'te dört, ikiye çevrildi, bu yüzden artık eşleşmiyor.

Çift tırnak içindeki örnek için, bash man sayfasından ikinci alıntıdan sonra ne olduğuna dikkat edin:

Ters eğik çizgi özel anlamını yalnızca şu karakterlerden biri izlediğinde korur: $, `,", \ veya newline.

Yani, tek sayıda ters eğik çizgi verdiğinizde, sıra , bitmeyen durumda \ceşit olacak şekilde sona erer c, ancak alıntılandığında, ters eğik çizgi özel anlamını kaybeder, bu yüzden \cgrep'e geçer. "Mümkün" ters eğik çizgiler (örneğin, örnek dosyanızla eşleşen bir desen oluşturanlar) aralığı bir aşağı kayar.


... ve sonra bazı tuhaflıklar var: örnek için: çift ​​tırnak içinde olduğu gibi kabuk tarafından çevrilmiş printf "\ntest"olsa bile, "test" ten önce bir yeni satır ekleyecektir ... (bu yüzden beklenen sonuç, "\ ntest", "ntest". Yazma alışkanlığını edinmeliyiz: ya da bir şekilde garipliğe dayanan bir sürü senaryo görüyorum"\n""n"printf "\\ntest"printf '\ntest'
Olivier Dulac 28:18

6

Bu bağlantıda bash Alıntılar ve Kaçış anlatıldı

Sorunuz ilk üç bölümle ilgilidir.

  • Karakter başına kaçış
  • Zayıf tırnak "çift tırnak"
  • Güçlü teklif 'tek teklifler'
  • ANSI C gibi dize alıntıları
  • I18N / L10N alıntılama (Uluslararasılaştırma ve Yerelleştirme) .

Aşağıda, dizelerin bashonları grepnasıl grepaktardıklarına ve bunları dahili olarak nasıl daha fazla yorumladıklarına dair bir grafik bulunmaktadır .

İlk önce bakalım echo "#ab\\cd" > file.
Olarak zayıf tırnaklı ( "") "#ab\\cd", \\bir kaçan \geçirilir ki file, tek bir sabit değer olarak \. Yani, fileiçerir ab\cd

Şimdi, komutlarınıza: Aşağıdaki grafik, her çağrıda gerçekte neler olup bittiğini görmenize yardımcı olabilir. *Dosya içeriğini örtüşen şablonları gösterir. Gerçekten sadece bash'ın kaçış kurallarını uygulama meselesi, web sayfasında olduğu gibi, daniel kullmann'ın zayıf alıntılama durumundan kaçan davranışı ifade ettiği cevabına özellikle dikkat edin .

Ters eğik çizgi özel anlamını yalnızca şu karakterlerden biri izlediğinde korur: $, `,", \ veya newline.


                            bash passes    grep further
                            to grep        resolves to         
grep -E ab\cd file            abcd           abcd   
grep -E ab\\cd file           ab\cd          abcd  
grep -E ab\\\cd file          ab\cd          abcd
grep -E ab\\\\cd file         ab\\cd         ab\cd    * 
grep -E ab\\\\\cd file        ab\\\cd        ab\cd    *
grep -E ab\\\\\\cd file       ab\\\cd        ab\cd    *    
grep -E ab\\\\\\\cd file      ab\\\cd        ab\cd    *
grep -E ab\\\\\\\\cd file     ab\\\\cd       ab\\cd

grep -E "ab\cd" file          ab\cd          abcd
grep -E "ab\\cd" file         ab\cd          abcd
grep -E "ab\\\cd" file        ab\\cd         ab\cd    *
grep -E "ab\\\\cd" file       ab\\cd         ab\cd    *
grep -E "ab\\\\\cd" file      ab\\\cd        ab\cd    *
grep -E "ab\\\\\\cd" file     ab\\\cd        ab\cd    *
grep -E "ab\\\\\\\cd" file    ab\\\\cd       ab\\cd    

grep -E 'ab\cd' file          ab\cd          abcd  
grep -E 'ab\\cd' file         ab\\cd         ab\cd    *
grep -E 'ab\\\cd' file        ab\\\cd        ab\cd    *
grep -E 'ab\\\\cd' file       ab\\\\cd       ab\\cd
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.