Bir dizeyi Bash'te normal ifadeyle nasıl eşleştirebilirim?


166

Ben verildiğinde bu yüzden bir işlev içeren bir bash senaryo yazmaya çalışıyorum .tar, .tar.bz2, .tar.gzvb dosya o dosya sıkıştırması ilgili anahtarlar ile tar kullanır.

If elif sonra ne ile biten görmek için dosya adını test ifadeleri kullanıyorum ve regex meta karakterleri kullanarak eşleştirmek için alamıyorum.

Komut satırında 'test' kullandığım komut dosyasını sürekli olarak yeniden yazmak için, aşağıdaki ifadenin çalışması gerektiğini düşündüm, mümkün olan her parantez, tırnak ve metakharat kombinasyonunu denedim ve hala başarısız.

test sed-4.2.2.tar.bz2 = tar\.bz2$; echo $?
(this returns 1, false)

Eminim problem basit bir sorundur ve her yere baktım, ama nasıl yapılacağını anlayamıyorum. Birisi bunu nasıl yapabileceğimi biliyor mu?

Yanıtlar:


268

Normal ifadeleri eşleştirmek için =~operatörü kullanmanız gerekir .

Bunu dene:

[[ sed-4.2.2.tar.bz2 =~ tar.bz2$ ]] && echo matched

Alternatif olarak, işleçle joker karakterler (normal ifadeler yerine) kullanabilirsiniz ==:

[[ sed-4.2.2.tar.bz2 == *tar.bz2 ]] && echo matched

Taşınabilirlik bir endişe değilse , daha güvenli ve daha güçlü [[yerine [veya kullanmanızı öneririz test. Bkz. Test arasındaki fark nedir [ve [[? detaylar için.


7
İkinci örnekte glob joker karakter eşleşmesine dikkat edin. [[]] İçinde *, geçerli dizindeki bir desenle eşleşen dosya adlarını eşleştirmek için genellikle olduğu gibi genişletilmez.Örneğiniz işe yarıyor, ancak * herhangi bir bağlam. Sadece [[]] içinde böyle çalışır. Aksi takdirde, varolan dosya adlarına genişler.
Alan Porter

7
Normal ifade tırnak kullanmaya çalıştı ve başarısız oldu; Bu cevap , bu çalışmanın yapılmasına yardımcı oldu, check="^a.*c$";if [[ "abc" =~ $check ]];then echo match;fi
Aquarius Power

Ayrıca regexp'in (perl'deki gibi) parantez içinde OLMAMASI gerektiğini unutmayın: [[ sed-4.2.2.tar.bz2 == "*tar.bz2" ]]işe yaramaz.
pevik

18
FWIW, olumsuzluk sözdizimi (yani eşleşmiyor ) [[ ! foo =~ bar ]].
Skippy le Grand Gourou

1
dash -n 1parametreyi desteklemez, otomatik olarak bir $REPLYdeğişkene koymaz. Dikkat et!

54

Bunu Yapacak Bir İşlev

extract () {
  if [ -f $1 ] ; then
      case $1 in
          *.tar.bz2)   tar xvjf $1    ;;
          *.tar.gz)    tar xvzf $1    ;;
          *.bz2)       bunzip2 $1     ;;
          *.rar)       rar x $1       ;;
          *.gz)        gunzip $1      ;;
          *.tar)       tar xvf $1     ;;
          *.tbz2)      tar xvjf $1    ;;
          *.tgz)       tar xvzf $1    ;;
          *.zip)       unzip $1       ;;
          *.Z)         uncompress $1  ;;
          *.7z)        7z x $1        ;;
          *)           echo "don't know '$1'..." ;;
      esac
  else
      echo "'$1' is not a valid file!"
  fi
}

Diğer Not

Yukarıdaki açıklamadaki Kova Gücü'ne yanıt olarak, We need to store the regex on a var

Değişken BASH_REMATCH'de Eğer ifadeyle eşleşen ve $ {BASH_REMATCH'de [n]} aşağıdaki parantez yani sarılmış n'inci grup maç olacak sonra ayarlanır ${BASH_REMATCH[1]} = "compressed"ve${BASH_REMATCH[2]} = ".gz"

if [[ "compressed.gz" =~ ^(.*)(\.[a-z]{1,5})$ ]]; 
then 
  echo ${BASH_REMATCH[2]} ; 
else 
  echo "Not proper format"; 
fi

(Yukarıdaki normal ifade, dosya adlandırma ve uzantılar için geçerli bir ifade değildir, ancak örnek için çalışır)


ayrıca BSD tar ile tüm biçimler için "tar xf" kullanabileceğinizi ve ayrı komutlara veya bu işleve gerek olmadığını unutmayın.
İyi Bir İnsan

aGNU katran veya pBSD katran üzerinde, sıkıştırma türünü uzantıdan otomatik olarak çıkarması gerektiğini açıkça belirtmek için. GNU tar aksi takdirde otomatik olarak yapmayacak ve @GoodPerson'ın BSD tar varsayılan olarak bunu yaptığı yorumundan tahmin ediyorum.
Mark K Cowan

7z paketi açabilir .. AR, ARJ, CAB, CHM, CPIO, CramFS, DMG, EXT, FAT, GPT, HFS, IHEX, ISO, LZH, LZMA, MBR, MSI, NSIS, NTFS, QCOW2, RAR, RPM, SquashFS , UDF, UEFI, VDI, VHD, VMDK, WIM, XAR ve Z. bkz. 7-zip.org
mosh

14

Burada yorum yapmak için yeterli temsilcim yok, bu yüzden dogbane'nin cevabını geliştirmek için yeni bir cevap gönderiyorum. Nokta . normal ifade içinde

[[ sed-4.2.2.tar.bz2 =~ tar.bz2$ ]] && echo matched

aslında 'tar.bz2' arasındaki değişmez nokta ile değil, herhangi bir karakterle eşleşir, örneğin

[[ sed-4.2.2.tar4bz2 =~ tar.bz2$ ]] && echo matched
[[ sed-4.2.2.tar§bz2 =~ tar.bz2$ ]] && echo matched

veya '\' ile kaçmayı gerektirmeyen herhangi bir şey. Katı sözdizimi

[[ sed-4.2.2.tar.bz2 =~ tar\.bz2$ ]] && echo matched

veya daha da sertleşebilir ve normal noktaya önceki noktayı da dahil edebilirsiniz:

[[ sed-4.2.2.tar.bz2 =~ \.tar\.bz2$ ]] && echo matched

9

Bash kullandığınız için, bunu yapmak için bir alt süreç oluşturmanıza gerek yoktur. İşte tamamen bash içinde gerçekleştiren bir çözüm:

[[ $TEST =~ ^(.*):\ +(.*)$ ]] && TEST=${BASH_REMATCH[1]}:${BASH_REMATCH[2]}

Açıklama: "İki nokta üst üste ve bir veya daha fazla boşluk" dizisinden önceki ve sonraki gruplar, kalıp eşleştirme operatörü tarafından BASH_REMATCH dizisinde saklanır.


1
Dizin 0'ın tam eşleşmeyi ve dizin 1 ve 2'nin grup eşleşmelerini içerdiğini unutmayın.
Rainer Schwarze

3
if [[ $STR == *pattern* ]]
then
    echo "It is the string!"
else
    echo "It's not him!"
fi

Benim için çalışıyor! GNU bash, version 4.3.11(1)-release (x86_64-pc-linux-gnu)


1
Bu son derece tehlikelidir; geçerli dizinde değişmez alt dize "desen" adında bir dosyanız olmadığından, yalnızca sizin için tanımlanmamış davranış olmadan davranır. Devam edin, böyle adlandırılmış dosyalar oluşturun ve alt dize genişletme, dosyalarla eşleşecek ve çok renkli heisenbugs ile her şeyi korkunç bir şekilde kıracaktır.
i336_

Ama ben bir deney yaptım: mevcut dizindeki `` desen, desen desen2 ve desen '' dosyaları ile . Bu komut dosyası beklendiği gibi çalışıyor. Lütfen bana test sonucunu verir misiniz? @ i336_
juan cortez

2
@ i336: Sanmıyorum. İçinde [[ ... ]], RHS topak desen yok değil genellikle yapacağı gibi, geçerli dizinde tho göre genişletmek.
user1934428

@ i336_ Hayır. [[...]]Bash içinde dosya adı genişletmesi yapılmıyor . Bash kılavuzunda,Word splitting and filename expansion are not performed on the words between the [[ and ]];
jinbeom hong

@jinbeomhong: TIL. Bunu bilmek güzel, teşekkürler!
i336_

2

shopt -s nocasematch

if [[ sed-4.2.2.$LINE =~ (yes|y)$ ]]
 then exit 0 
fi
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.