Bash if ifadesinde normal ifade eşleşmesi


89

Burada neyi yanlış yaptım?

Boşluk, küçük harf, büyük harf veya sayı içeren herhangi bir dizeyle eşleşmeye çalışılıyor. Özel karakterler de hoş olurdu ama bence bu bazı karakterlerden kaçmayı gerektiriyor.

TEST="THIS is a TEST title with some numbers 12345 and special char *&^%$#"

if [[ "$TEST" =~ [^a-zA-Z0-9\ ] ]]; then BLAH; fi

Bu açıkça sadece üst, alt, sayılar ve boşlukları test eder. Yine de çalışmıyor.

* GÜNCELLEME *

Sanırım daha spesifik olmalıydım. İşte gerçek gerçek kod satırı.

if [[ "$TITLE" =~ [^a-zA-Z0-9\ ] ]]; then RETURN="FAIL" && ERROR="ERROR: Title can only contain upper and lowercase letters, numbers, and spaces!"; fi

* GÜNCELLEME *

./anm.sh: line 265: syntax error in conditional expression
./anm.sh: line 265: syntax error near `&*#]'
./anm.sh: line 265: `  if [[ ! "$TITLE" =~ [a-zA-Z0-9 $%^\&*#] ]]; then RETURN="FAIL" && ERROR="ERROR: Title can only contain upper and lowercase letters, numbers, and spaces!"; return; fi'

Gerçekte hangi kabuğu kullanıyorsunuz? / bin / sh? / bin / bash? / bin / csh?
Willem Van Onsem

8
Normal ifadeyi bir değişkene koymak daha güvenlidir. re='...whatever...'; [[ $string =~ $re ]](tırnak işaretleri olmadan - bu, onlarsız işe yarayacak bir şeyi bozacakları nadir durumlardan biridir).
Charles Duffy

3
Bunun yerine ödevin etrafına tek tırnak işareti koyun. Çift tırnak işaretleri özel karakterleri tam olarak korumaz.
2013

Çok teşekkürler Charles! Yine de onu bir değişkene koymamak sorun değil, ama hiç alıntılanmamalıdır! Örneğin: [[ $var =~ .* ]]normal ifade .*(herhangi bir şey) eşleşmesi için . Sanırım tırnak kullanırsanız, alıntıların kendilerinin normal ifadenin bir parçası olduğu düşünülür ...
Stéphane

4
Gotcha özeti Bulduğum: (1.) tekli tırnakları pattern='^hello[0-9]*$'(2.) kullanarak normal ifadeyi eşleştirmeye ihtiyaç duyuyorsanız deseni alıntı yapmayın çünkü normal ifade desen eşleşmesini DEVRE DIŞI BIRAKIR. (yani ifade [[ "$x" =~ $pattern ]], normal ifade kullanılarak eşleşir ve ifade [[ "$x" =~ "$pattern" ]]normal ifade eşleşmesini devre dışı bırakır ve ile eşdeğerdir[[ "$x" == "$pattern" ]] ).
Trevor Boyd Smith

Yanıtlar:


184

Bash'in [[ ]]inşası hakkında bilinmesi gereken birkaç önemli şey var . İlk:

Sözcük bölme ve yol adı genişletme, [[ve arasındaki sözcüklerde gerçekleştirilmez ]]; yaklaşık genişletme, parametre ve değişken genişletme, aritmetik genişletme, komut ikamesi, işlem ikamesi ve alıntı kaldırma gerçekleştirilir.

İkinci şey:

Ek bir ikili işleç, '= ~' mevcuttur, ... işlecin sağındaki dize, genişletilmiş bir normal ifade olarak kabul edilir ve buna göre eşleştirilir ... Eşleşmeye zorlamak için modelin herhangi bir kısmı tırnak içine alınabilir bir dize olarak .

Sonuç olarak, $vher iki tarafında da =~o değişkenin değerine genişletilecek, ancak sonuç sözcük ayrımı veya yol adı genişletme olmayacaktır. Diğer bir deyişle, değişken genişletmeleri sol tarafta alıntılanmamış bırakmak tamamen güvenlidir, ancak değişken genişletmelerin sağ tarafta olacağını bilmeniz gerekir.

Yazdığınız Yani eğer: [[ $x =~ [$0-9a-zA-Z] ]], $0regex yorumlanır önce sağdaki regex içine muhtemelen (derlemeye başarısız olmasına regex neden olacaktır, genişletilecek genişlemesi sürece $0kimin ASCII değeri az olan bir rakam ya da noktalama sembolüyle uçları bir rakam). Sağ taraftan böyle alıntı yaparsanız, sağ taraf [[ $x =~ "[$0-9a-zA-Z]" ]]normal bir dize olarak değerlendirilir, normal bir dize olarak değerlendirilir (ve $0yine de genişletilir). Bu durumda gerçekten istediğiniz şey[[ $x =~ [\$0-9a-zA-Z] ]]

Benzer şekilde, normal ifade yorumlanmadan önce [[ve arasındaki ifade ]]kelimelere bölünür. Bu nedenle, normal ifadedeki boşluklardan kaçınılması veya alıntı yapılması gerekir. Eğer harf, rakam veya boşluk maç istiyorsa şunu kullanabilirsiniz: [[ $x =~ [0-9a-zA-Z\ ] ]]. Benzer şekilde, #alıntı yapılmazsa bir yorum başlatacak gibi diğer karakterlerden de kaçınılması gerekir . Elbette, modeli bir değişkene koyabilirsiniz:

pat="[0-9a-zA-Z ]"
if [[ $x =~ $pat ]]; then ...

Bash'in sözlüğünden geçmek için kaçılması veya alıntı yapılması gereken çok sayıda karakter içeren normal ifadeler için, birçok kişi bu stili tercih eder. Ancak dikkat edin: Bu durumda, değişken genişletmeyi alıntı yapamazsınız :

# This doesn't work:
if [[ $x =~ "$pat" ]]; then ...

Son olarak, yapmaya çalıştığınız şeyin değişkenin yalnızca geçerli karakterler içerdiğini doğrulamak olduğunu düşünüyorum. Bu kontrolü yapmanın en kolay yolu, geçersiz bir karakter içermediğinden emin olmaktır. Başka bir deyişle, şöyle bir ifade:

valid='0-9a-zA-Z $%&#' # add almost whatever else you want to allow to the list
if [[ ! $x =~ [^$valid] ]]; then ...

!testi geçersiz kılar, "eşleşmiyor" operatörüne dönüştürür ve bir [^...]normal ifade karakter sınıfı "dışındaki herhangi bir karakter" anlamına gelir ....

Parametre genişletme ve normal ifade operatörlerinin birleşimi, bash düzenli ifade sözdizimini "neredeyse okunabilir" hale getirebilir, ancak yine de bazı bilgiler vardır. (Her zaman yok mu?) Biri koymak olamazdı ki ]içine $validbile $validçok başlayan haricinde, sözleri kaydedildi. (Bu bir Posix normal ifade kuralıdır: ]Bir karakter sınıfına dahil etmek istiyorsanız , baştan gitmesi gerekir. -Başa veya sona gidebilir, bu nedenle ikisine de ihtiyacınız varsa ]ve -şununla başlamalısınız:] ve bitmeniz- , regex giden ifadeyi "Ben ne yaptığımı biliyorum": [][-])


6
Sadece şunu belirtmek isterim ki "! ~" İle eşleşmiyor "operatör" doğru değil. Her iki kullanım if ! [[ $x =~ $y ]]ya daif [[ ! $x =~ $y ]]
alkol

shellchecker aynı fikirde değil ...SC2076: Don't quote rhs of =~, it'll match literally rather than as a regex.
Leonardo

4
@leonard: Bunun "değişken genişlemesini alıntı yapamazsınız" ifademden ve "Bu çalışmıyor" yorumundan farkı nedir? Bununla ilgili belirsiz olan nedir?
rici

1
@jinbeomhong: İfadenin kendisi her zamanki gibi boşluk kullanılarak kelimelere ayrılır. Ancak parametre ve komut genişletmeleri kelimeye bölünmez.
rici

1
@jinbeomhong: Bash kılavuzundan farklı bir şey söylemiyorum. " kelimeler arasında [[ve ]]programın metin ayrı tutulur, aynı şekilde komut satırları kelimelere çözümlenir". Komut satırlarının aksine, sözcükler genişletmelerden sonra bölünmez.
rici

30

Birinin değişkenleri kullanarak bir örnek istemesi durumunda ...

#!/bin/bash

# Only continue for 'develop' or 'release/*' branches
BRANCH_REGEX="^(develop$|release//*)"

if [[ $BRANCH =~ $BRANCH_REGEX ]];
then
    echo "BRANCH '$BRANCH' matches BRANCH_REGEX '$BRANCH_REGEX'"
else
    echo "BRANCH '$BRANCH' DOES NOT MATCH BRANCH_REGEX '$BRANCH_REGEX'"
fi

13

Bunun için kullanmayı tercih ederim [:punct:]. Ayrıca a-zA-Z09-9şunlar olabilir [:alnum:]:

[[ $TEST =~ ^[[:alnum:][:blank:][:punct:]]+$ ]]

-1

Ya da bu soruya bakıyor olabilirsiniz çünkü benim yaptığım gibi aptalca bir yazım hatası yapmışsınız ve = ~ tersine ~ =

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.