1

I'd like to loop over each pattern found and have access to the different capture groups inside the loop, possibly with grep or awk (I'd like to stick with them if possible to avoid to learn a 3rd one, but if really necessary, I'll learn another one!)

Does something like:

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

exist?


Sample text:

blah12687hello=123
nothingthatmatches
blah3211hello=123456
blah15butnottheotherpattern

With the loop mentioned before, it should output:

blah12687hello=123
12687
<it should run the command dosomethingwith 123>
blah3211hello=123456
3211
<it should run the command dosomethingwith 123456>
  • 1
    The bash shell itself provides one, why wouldn't you use it? And capture groups of Awk/grep are close constrained in a sense it will not be available in the shell context by only within their own. Do you have a sample of text (or) file content to better explain your question? – Inian Oct 4 '17 at 14:58
  • @Inian the question comes from here where I was wondering if it's possible to have the two first lines of "The job" condensed into one single awk or grep and let them capture the groups... Can you show an example of what you mean with bash only? (I updated with a sample example). – Basj Oct 4 '17 at 15:09
  • blah and hello= patterns are always fixed patterns? if yes, it's easy job for awk or even sed otherwise solution will be a bit complex – αғsнιη Oct 4 '17 at 15:14
  • @αғsнιη Yes, fixed patterns. – Basj Oct 4 '17 at 15:18
  • @Inian I added a sample and required output (the requirements are detailed in the loop before) – Basj Oct 4 '17 at 15:18
2

The bash shell by itself provides a way to do regular expression matching process the captured groups as conveniently needed.

The =~ operator within a double brackets test expression, [[ with the match string on the left side of the operator and regular expression as the right operand.

if [[ "$str" =~ $re ]]; then

If the expression matches the string, the matched part of the string is stored in the BASH_REMATCH array which can be looped over to access the individual captured groups. The exit status is 0 if the regexp matches, 1 if it doesn't, and 2 if the expression is invalid.


As far as your example is concerned, assuming you have the input lines stored in an array and the words blah and hello are fixed patterns

#!/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

As you can see in the code above, once we match the regex to be true we can loop over the BASH_REMATCH array to print each of the captured group. The overall script output would be something like

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.

As you can see the BASH_REMATCH[0] always contains the part of the string that was successfully matched by the regex, and the individual captured groups can be accessed from index 1 onward. You can write custom logic to process each of the captured group which is what you originally intended to do.


If you are interested in reading a file input, just use a while loop with input re-direction on the file to be processed

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.