2016-12-14 17 views
7

Bir dizede birden çok yerde eşleşmesi gereken bir regex desenim var. Tüm maç gruplarını tek bir diziye almak ve sonra her bir öğeyi yazdırmak istiyorum. YaniBash regex ungreedy maçı

, bunu çalışıyorum:

#!/bin/bash 

f=$'\n\tShare1 Disk\n\tShare2 Disk\n\tPrnt1 Printer' 
regex=$'\n\t(.+?)\\s+Disk' 
if [[ $f =~ $regex ]] 
then 
    for match in "${BASH_REMATCH[@]}" 
    do 
     echo "New match: $match" 
    done 
else 
    echo "No matches" 
fi 

Sonuç:

beklenen sonuç olurdu
New match: 
    Share1 Disk 
    Share2 Disk 
New match: Share1 Disk 
    Share2 

Ben çünkü çalışmıyor düşünüyorum

New match: Share1 
New match: Share2 

benim .+? açgözlü eşleştiriyor. Bu yüzden bunun nasıl baştan regex ile gerçekleştirilebileceğini araştırdım. Ancak herkes, grep'i perl regex ile kullanmayı önerir.

Fakat elbette başka bir yolu olmalı. Ben [^\\s]+ gibi belki bir şey düşünüyordum .. Ama bunun için çıkış oldu:

New match: 
    Share1 Disk 
New match: Share1 

... Herhangi bir fikir?

+0

Bir fikre:? Şeylerin olsa kendi hatları üzerinde olduğu için, bir şeyler bölmek ve benzeri her satıra desen uygulamak için bu kullanmayı deneyebilirsiniz . +? ' Bu, bulunan bir boşluk olana kadar karakterlerle eşleşecektir. – Rahul

+0

@Rahul veya '\ S +?' –

+0

Her ikisi de, [^ \\ s] + 'ile benim sorduğum sorudan daha önce bahsettiğim aynı sonucu verir. Bilmiyorum ki, '' 'bashta bile destekleniyor, yani bu bağlamda demek istedim ..' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' anlamına gelmez. – Forivin

cevap

5

Burada birkaç sorun var. İlk olarak, BASH_REMATCH öğesinin ilk öğesi, yakalama grubuna değil, desenle eşleşen dizenin tamamıdır. Bu nedenle, yakalama gruplarında bulunanları almak için ${BASH_REMATCH[@]:1}'u kullanmak istersiniz. Bununla birlikte, bash regex dizede birden çok kez tekrarlanmayı desteklemez, bu yüzden bash muhtemelen bu iş için doğru araç değildir. Üste | `Kullanmak [^ \\ s] +` yerine olacaktır

f=$'\n\tShare1 Disk\n\tShare2 Disk\n\tPrnt1 Printer' 
regex=$'\t(\S+?)\\s+Disk' 
while IFS=$'\n' read -r line; do 
    if [[ $line =~ $regex ]] 
    then 
     printf 'New match: %s\n' "${BASH_REMATCH[@]:1}" 
    else 
     echo "No matches" 
    fi 
done <<<"$f"