Chtěl bych opakovat každý nalezený vzor a mít přístup k různým skupinám zachycení uvnitř smyčky, možná pomocí grep
nebo awk
(Chtěl bych s nimi zůstat, pokud je to možné, abych se vyhnul tomu, abych se naučil 3., ale pokud to bude opravdu nutné, naučím se další!)
Dělá něco jako:
awk-or-grep -E '(blah(.*)hello=(.*))' sampletext | while read -r l; do
echo $0 #1st capture group
echo $1 #2nd catpure group
dosomethingwith $2 #3rd capture group
done
existují?
Ukázkový text:
blah12687hello=123
nothingthatmatches
blah3211hello=123456
blah15butnottheotherpattern
S výše zmíněnou smyčkou by měl výstup:
blah12687hello=123
12687
<it should run the command dosomethingwith 123>
blah3211hello=123456
3211
<it should run the command dosomethingwith 123456>
Přijatá odpověď:
bash
Shell sám o sobě poskytuje způsob, jak zpracovat porovnávání regulárních výrazů se zachycenými skupinami podle potřeby.
=~
operátor v testovacím výrazu s dvojitými závorkami, [[
se srovnávacím řetězcem na levé straně operátoru a regulárním výrazem jako pravým operandem.
if [[ "$str" =~ $re ]]; then
Pokud výraz odpovídá řetězci, odpovídající část řetězce je uložena v BASH_REMATCH
pole, které lze přepnout do smyčky pro přístup k jednotlivým zachyceným skupinám. Stav ukončení je pokud se regulární výraz shoduje,
1
pokud ne, a 2
pokud je výraz neplatný.
Pokud jde o váš příklad, za předpokladu, že máte vstupní řádky uložené v poli a slova blah
a hello
jsou pevné vzory
#!/usr/bin/env bash
exampleStr=('blah12687hello=123' 'nothingthatmatches' 'blah3211hello=123456' 'blah15butnottheotherpattern')
re='blah([[:digit:]]+)hello=([[:digit:]]+)'
for str in "${exampleStr[@]}"; do
if [[ "$str" =~ $re ]]; then
for group in "${BASH_REMATCH[@]}"; do
printf "%s\n" "$group"
done
else
printf "No match \n"
fi
done
Jak můžete vidět ve výše uvedeném kódu, jakmile přiřadíme regulární výraz tak, aby byl pravdivý, můžeme opakovat BASH_REMATCH
pole pro tisk každé zachycené skupiny. Celkový výstup skriptu by byl něco jako
blah12687hello=123 # Value of BASH_REMATCH[0]
12687 # Value of BASH_REMATCH[1]
123 # Value of BASH_REMATCH[2]
Regex not matches.
blah3211hello=123456
3211
123456
Regex not matches.
Jak můžete vidět BASH_REMATCH[0]
vždy obsahuje tu část řetězce, která byla úspěšně porovnána s regulárním výrazem, a k jednotlivým zachyceným skupinám lze přistupovat z indexu 1
Kupředu. Můžete napsat vlastní logiku pro zpracování každé zachycené skupiny, což je to, co jste původně zamýšleli udělat.
Máte-li zájem o čtení vstupu souboru, stačí použít while
smyčka s přesměrováním vstupu na soubor, který má být zpracován
while IFS= read -r line; do
if [[ "$line" =~ $re ]]; then
for group in "${BASH_REMATCH[@]}"; do
printf "%s\n" "$group"
done
else
printf "No match \n"
fi
done < inputFile.txt