0

Question in short

Given a string, how to retrieve several sub-strings given a regex?

echo "hello world 15 42" | grep -P ".*([0-9]+) ([0-9]+)";

This unfortunately return the full matching string, not the 15 and 42 separately. Ideally some variable would recover both of them so I could use them:

echo "First: $0, Second: $1"; # echo is only an example

More of the context

For an install script, it needs to download the relevant file from an URL (with wget), however, the specific file name is unknown, so the script need to first download the index.html to extract file-names, extract the version numbers and re-construct the full URL.

wget 2>/dev/null -O - http://...../directory/ | grep -P "<a href=....
wget "http://..../directory/file-$1-revision-$2.gz" -O downloaded.gz
2

Use bash regex matching and access the builtin BASH_REMATCH array

s="hello world 15 42"
re='.*([0-9]+) ([0-9-]+)'
if [[ $s =~ $re ]]; then
    for key in "${!BASH_REMATCH[@]}"; do 
        printf "%s\t%s\n" "$key" "${BASH_REMATCH[$key]}"
    done
fi
0   hello world 15 42
1   5
2   42
  • Why is the BASH_REMATCH[$key] printing 5 and not 15? – Adrian Maire Sep 17 '17 at 13:53
  • I learn a lot understanding this code, thanks you. It worked. – Adrian Maire Sep 17 '17 at 15:21
  • Because .* is greedy. Some of the other answers here have adjusted the regex – glenn jackman Sep 17 '17 at 15:25
1

I would use an array:

myArray=($(echo "hello world 15 42" | egrep -o '([0-9]+)'))

Access the first substring:

echo ${myArray[0]}
15

...and the second:

echo ${myArray[1]}
42
  • In this case, where the results are on separate lines, I'd use mapfile -t myArray < <(echo ... | egrep -Eo ...) – glenn jackman Sep 17 '17 at 13:35
  • It does not really answer the question: you don't get the values of the regex, but changed the regex for matching several substring. If (for instance) you add a string between hello and world, myArray would contain 3 values and the result would be wrong. – Adrian Maire Sep 17 '17 at 13:42
  • Do feel free to adapt the regex in whatever way suits your purpose best. The array method works with the original regex as well. Best regards! – maulinglawns Sep 17 '17 at 13:46
  • The problem is: myArray[n] is not related with the capture parenthesis. Try myArray=($(echo "hello wonderful world 15 42" | egrep -o ".*([0-9]+) ([0-9]+)")); echo ${myArray[3]}, or myArray=($(echo "hello world 15 42" | egrep -o ".*([0-9]+) ([0-9]+)")); echo ${myArray[3]} You get 15 or 42 depending on the starting string. – Adrian Maire Sep 17 '17 at 13:58
  • @AdrianMaire Umm... sorry, you've lost me. Apparently I have completely misunderstood the question. – maulinglawns Sep 17 '17 at 13:59
1
> greparray=($(echo "hello world 15 42" | grep -Eo "[0-9]+ [0-9]+"))
> echo ${greparray[1]}
42

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.