2009-08-07 13 views
14

Mam plik tekstowy z różnymi wpisami w nim. Każda pozycja zakończona jest linią zawierającą wszystkie gwiazdki.Jak przypisać dopasowanie mojego wyrażenia regularnego do zmiennej?

Chciałbym użyć poleceń powłoki do parsowania tego pliku i przypisania każdego wpisu do zmiennej. Jak mogę to zrobić?

Oto przykładowy plik wejściowy:

 
*********** 
Field1 
*********** 
Lorem ipsum 
Data to match 
*********** 
More data 
Still more data 
*********** 

Oto co moje rozwiązanie wygląda tak daleko:

#!/bin/bash 
for error in `python example.py | sed -n '/.*/,/^\**$/p'` 
do 
    echo -e $error 
    echo -e "\n" 
done 

Jednak to właśnie przypisuje każde słowo w dopasowanego tekstu do $ błędu, raczej niż cały blok.

Odpowiedz

23

Jestem zaskoczony, że nie widzę tutaj rodzimego rozwiązania bash. Tak, bash ma wyrażenia regularne. Możesz znaleźć mnóstwo losowych dokumentów online, szczególnie jeśli w zapytaniu podasz "bash_rematch" lub po prostu przejrzysz strony man. Oto głupi przykład zaczerpnięty z here i nieco zmodyfikowany, który wypisuje cały mecz, a także wszystkie przechwycone mecze, dla wyrażenia regularnego.

if [[ $str =~ $regex ]]; then 
    echo "$str matches" 
    echo "matching substring: ${BASH_REMATCH[0]}" 
    i=1 
    n=${#BASH_REMATCH[*]} 
    while [[ $i -lt $n ]] 
    do 
     echo " capture[$i]: ${BASH_REMATCH[$i]}" 
     let i++ 
    done 
else 
    echo "$str does not match" 
fi 

Ważne jest to, że nieco rozszerzony testy [[ ... ]] używając jego REGEX porównania =~ sklepów cały mecz w ${BASH_REMATCH[0]} i złapanych meczów ${BASH_REMATCH[i]}.

+1

Rzeczywiście, byłoby miło, gdyby istniał ostateczny przewodnik po bashowaniu wyrażeń regularnych, ale jak powiedział @Jefromi, jest to po prostu garść przypadkowości. – g33kz0r

+0

@Noah: Ze strony podręcznika: "ciąg po prawej stronie operatora jest traktowany jako rozszerzone wyrażenie regularne i odpowiednio do niego dopasowany (jak w regex (3)." Więc jest to rozszerzone w standardzie POSIX, tak? Wydaje się ... dość definitywne: – Cascabel

+0

To wszystko dobrze i dobrze, Jefromi, ale to nie jest diveintobashregex.org – g33kz0r

0

w zależności od tego, co chcesz zrobić ze zmiennymi

awk ' 
f && /\*/{print "variable:"s;f=0} 
/\*/{ f=1 ;s="";next} 
f{ 
    s=s" "$0 
}' file 

wyjściowa:

# ./test.sh 
variable: Field1 
variable: Lorem ipsum Data to match 
variable: More data Still more data 

wyżej prostu drukuje je. jeśli chcesz, przechowuj w tablicy do późniejszego użycia ... np. array [++ d] = s

1

Jeśli chcesz zrobić to w Bash, możesz zrobić coś takiego. Wykorzystuje globbing zamiast wyrażeń regularnych (The extglob opcja powłoka umożliwia rozszerzoną dopasowywania wzorców, dzięki czemu możemy dopasować linię składającą się tylko z gwiazdkami).

#!/bin/bash 
shopt -s extglob 
entry="" 
while read line 
do 
    case $line in 
     +(\*)) 
      # do something with $entry here 
      entry="" 
      ;; 
     *) 
      entry="$entry$line 
" 
      ;; 
    esac 
done 
0

rekordy Dzielenie w (ba) sh nie jest tak łatwe, ale może Zrób to za pomocą IFS, aby podzielić na pojedyncze znaki (po prostu ustaw IFS = '*' przed twoją pętlą for, ale to generuje wiele pustych rekordów i jest problematyczne, jeśli jakikolwiek rekord zawiera '*'). Oczywistym rozwiązaniem jest użycie perl lub awk i użycie RS do podziału rekordów, ponieważ te narzędzia zapewniają lepsze mechanizmy podziału rekordów. Rozwiązaniem hybrydowym jest użycie perla do dzielenia rekordów, a perl wywołuje twoją funkcję bash z pożądanym rekordem. Na przykład:

#!/bin/bash 

foo() { 
    echo record start: 
    echo "[email protected]" 
    echo record end 
} 
export -f foo 

perl -e "$/='********'; while(<>){chomp;system(\"foo '\$_'\")}" << 'EOF' 
this is a 2-line 
record 
******** 
the 2nd record 
is 3 lines 
long 
******** 
a 3rd * record 
EOF 

To daje następujący wynik:

 
record start: 
this is a 2-line 
record 

record end 
record start: 

the 2nd record 
is 3 lines 
long 

record end 
record start: 

a 3rd * record 

record end 
+0

Należy zauważyć, że skrypt podany tutaj prawie na pewno wymaga/bin/sh do bash. –

1

spróbuj umieścić w cudzysłowie polecenia.

#!/bin/bash 
for error in "`python example.py | sed -n '/.*/,/^\**$/p'`" 
do 
    echo -e $error 
    echo -e "\n" 
done 
Powiązane problemy