Bash'ta beklenmeyen karakterle eşleşen köşeli ayraç ifadesi (aralıksız)


20

Linux'ta bash kullanıyorum. Aşağıdaki if ifadesinden bir başarı elde ediyorum, ancak bu bir başarısız kodu döndürmemelisiniz?

if [[  = [⅕⅖⅗] ]] ; then echo yes ; fi

Kare, karakterlerin hiçbirine eşit DEĞİLDİR, bu yüzden neden bir başarı kodu aldığımı anlamıyorum.

Benim durumumda çift parantez tutmak benim için önemli.

Bu senaryoda bir aralık yapmanın başka bir yolu var mı, yoksa başka öneriler var mı?


2
Muhtemelen, bulunduğunuz yerde tanımlanmamış bir sıralama düzenine sahip olan tüm karakterlerin bir sonucu (ve böylece aynı şekilde sıralama). Austin grubunda devam eden, ilgili tartışmaya bakın . Düzeltmek için yerel ayarı C olarak değiştirin .
Stéphane Chazelas

1
Maalesef, Ctek baytlık karakterler olmadığı için burada yapmayacak. C.UTF-8mümkün olduğunda yapardı.
Stéphane Chazelas

11
Tebrikler, ilk sorunuzda bir Austin Group iş parçacığı olan Stéphane'yi çağırmayı başardınız. En azından bir İnternet'in değerine değecek. Ya da ⅘ ve hatta ■ İnternetler, görünüşe göre bunlar aynı. Unix ve Linux'a hoş geldiniz , lütfen ilginç sorular getirmeye devam edin.
derobert

Yanıtlar:


29

Bu, aynı sıralama düzenine sahip karakterlerin bir sonucudur.

Ayrıca şunu fark edeceksiniz:

sort -u << EOF




EOF

yalnızca bir satır döndürür.

Yada bu:

expr  = 

true değerini döndürür (POSIX'in gerektirdiği gibi).

GNU sistemleri ile gönderilen çoğu yerel ayar, aynı sıralama düzenine sahip bir dizi karaktere (ve hatta karakter dizilerine (harmanlama dizileri)) sahiptir. Bu ■ ⅕⅖⅗ olanlar için, bunun nedeni, siparişin tanımlanmadığı ve sırası tanımlanmayan karakterlerin GNU sistemlerinde aynı sıralama düzenine sahip olmalarıdır. Açıkça Ș ve Ş gibi aynı sıralama düzenine sahip olarak tanımlanan karakterler vardır (yine de benim için açık bir gerçek mantık veya tutarlılık yoktur).

Bu oldukça şaşırtıcı ve sahte davranışların kaynağıdır. Austin grubu (POSIX ve Single UNIX Spesifikasyonu'nun arkasındaki gövde) posta listesinde bu konuyu çok yakın bir zamanda gündeme getirdim ve tartışma 2015-04-03 itibariyle hala devam ediyor.

Bu durumda, nerede ve aynı şekilde [y]eşleşmesi gerekip gerekmediği benim için belirsizdir, ancak köşeli ayraç ifadesinin bir harmanlama öğesiyle eşleşmesi gerektiği için, bu davranışın beklendiğini gösterir.xxybash

Her durumda, sanırım [⅕-⅕]ya da en azından [⅕-⅖]eşleşmelidir .

Farklı araçların farklı davrandığını fark edeceksiniz. ksh93 bash, GNU gibi davranır grepveya seddavranmaz. Diğer bazı mermilerin farklı davranışları vardır, bazıları yashdaha fazla arabası gibi .

Tutarlı bir davranışa sahip olmak için, tüm karakterlerin farklı şekilde sıralandığı bir yerel ayara ihtiyacınız vardır. C yerel ayarı tipiktir. Bununla birlikte, çoğu sistemde C yerelinde ayarlanan karakter ASCII'dir. GNU sistemlerinde, genellikle C.UTF-8UTF-8 karakteri üzerinde çalışmak için kullanılabilecek bir yerel ayara erişebilirsiniz .

Yani:

(export LC_ALL=C.UTF-8; [[  = [⅕⅖⅗] ]])

veya standart eşdeğeri:

(export LC_ALL=C.UTF-8
 case  in ([⅕⅖⅗]) true;; (*) false; esac)

yanlış döndürmelidir.

Başka bir alternatif, yalnızca LC_COLLATEGNU sistemlerinde çalışacak olan C'ye ayarlamak , ancak çok baytlı karakterin sıralama düzenini belirleyemediği diğerlerine değil.


Bunun bir dersi, eşitliğin , dizeleri karşılaştırma söz konusu olduğunda bekleneceği kadar açık bir kavram olmadığıdır. Eşitlik, en katıdan en katıya doğru anlamına gelebilir.

  1. Aynı sayıda bayt ve tüm bayt bileşenleri aynı değere sahiptir.
  2. Aynı sayıda karakter ve tüm karakterler aynıdır (örneğin, geçerli karakter kümesindeki aynı kod noktasına bakın).
  3. İki dize, yerel ayarın harmanlama algoritmasına göre aynı sıralama düzenine sahiptir (yani, ne <b ne de b> a doğrudur).

Şimdi, 2 veya 3 için, her iki dizenin geçerli karakterler içerdiğini varsayar. UTF-8 ve diğer bazı kodlamalarda, bazı bayt dizileri geçerli karakterler oluşturmaz.

Bu nedenle veya bazı karakterler birden fazla olası kodlamaya sahip olabileceğinden, 1 ve 2 mutlaka eşdeğer değildir. Yani tipik ISO-2022-JP gibi durum bilgisi kodlamaların durum Aolarak ifade edilebilir 41ya da 1b 28 42 41( 1b 28 42ASCII için anahtara diziyi olmak ve bir fark yaratmak olmaz, istediğiniz gibi kişilerin birçoğu olarak ekleyebilirsiniz), I gerçi bu tür kodlamanın hala kullanımda olmasını beklemezsiniz ve GNU araçları en azından genellikle onlarla düzgün çalışmaz.

Ayrıca, GNU olmayan çoğu yardımcı programın 0 bayt değeriyle (ASCII'deki NUL karakteri) baş edemeyeceğine dikkat edin.

Bu tanımların hangisi yardımcı programa ve yardımcı program uygulamasına veya sürümüne bağlıdır. POSIX bu konuda% 100 net değil. C yerelinde, 3'ün hepsi eşdeğerdir. O YMMV'nin dışında.


1 ve 2'nin farklı olduğu bir diğer yaygın durum Unicode'da karakterleri birleştirmek gibi şeylerle ilgilidir.
Gilles 'SO- kötü olmayı kes'

@Gilles, karakterleri birleştirmek kendi karakterleri. Kombinasyon bir grafik / hücre oluşturur, ancak yine de birkaç karakterden oluşur. é (U + 00E9) ve é (e ardından U + 0301) aynı grafiktir, ancak iki farklı karakter dizisidir (en azından POSIX API'leri açısından). 1 ve 2'de bunlar farklı olurdu. 3'e kadar, U + 0301'in tüm harmanlama ağırlıklarını "IGNORE" olarak ayarladıysa aynı düşünebilirler, ancak genellikle aksanların sırasına karar vermek istediği için genellikle durum böyle değildir.
Stéphane Chazelas

Genellikle aynı ipin düşünülmesi éve olması arzu edilir , ancak olmamalıdır e. POSIX'in harmanlama sırası kavramı nadiren doğrudur, karakterlere çok fazla dayanır ve dizeleri sıralamanın en yaygın yollarını açıklamaz (örneğin, Fransızca sözlükler kelimeleri sıralamak için sözlükbilimsel bir sipariş kullanmazlar: yok sayılan aksanlarla ilk sözlükbilimsel geçiş yaparlar ve sonra bağları belirlemek için aksanları kullanın).
Gilles 'SO- kötü olmayı kes'

@Gilles, evet. Bu yüzden glibc yerellerinde aynı sıralama düzenine (kasıtlı olarak) sahip olan karakterlerin çok az mantıklı olduğunu söyleyebilirim. É ve é genellikle, kanonik ayrışma gibi ilk önce dizelerde bazı dönüşümler yapılarak ele alınır (büyük / küçük harf duyarsız sıralama / eşleştirme yapmak istediğinizde önce küçük harfe dönüştürmeye benzer). Konuyla ilgili bazı iyi referanslar için ICU kılavuzuna da bakın .
Stéphane Chazelas

@Gilles, POSIX yerel ayar algoritması içindeki ağırlıklar Fransızca sözlük sıralamasını yapabilir. Ağırlıklar bu şekilde çalışır. İlk geçiş birincil ağırlıkları kullanır (burada e ve é (ve E ve É) aynıdır ve birleştirici akut aksan göz ardı edilir) ikinci geçiş (eşitse) aksanları kontrol eder, 3. geçiş kapitalizasyonu ...
Stéphane Chazelas

-3

Yanlış yapıyorsunuz =ve ==aynı değilsiniz.

Şu örnekleri deneyin:

if [[ "■" == "[⅕⅖⅗]" ]] ; then echo yes ; else echo no ; fi

if [[ "1" == "1" ]] ; then echo yes ; else echo no ; fi

if [[ "■" == "■" ]] ; then echo yes ; else echo no ; fi

1
Bu doğru değil. POSIX, operatörün =eşitliği kontrol etmek için kullanılması gerektiğini belirtir . Sorun eksik tırnaklar, operatör değil.
scai

1
Ayrıca "= işleci == ile eşdeğerdir" bölümünde de man bashyazıyor [[.
michas

1
@scai, POSIX [[...]]operatörü belirtmiyor . Ve = ve == kabukları aynıdır (ksh / bash / zsh) ve desen eşleştirme için eşitlik değil.
Stéphane Chazelas

Bir kalıpla karşılaştırılırken, kalıp alıntılanmamalı, aksi takdirde gerçek bir dize olarak alınmalı, dolayısıyla ilk testte "hayır" olmalıdır.
xhienne
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.