-1

From a variable how to extract integers that will be in format *\d+.\d+.\d+* (4.12.3123) using bash.

filename="xzxzxzxz4.12.3123fsfsfsfsfsfs" 

I have tried:

filename="xzxzxzxz4.12.3123fsfsfsfsfsfs" 
if [[ "$filename" =~ (.*)(\d+.\d+.\d+)(.*) ]]; then 
    echo ${BASH_REMATCH} 
    echo ${BASH_REMATCH[1]} 
    echo ${BASH_REMATCH[2]} 
    echo ${BASH_REMATCH[3]} 
else 
    echo 'nej' 
fi 

which does not work.

Inian
  • 80,270
  • 14
  • 142
  • 161
ap3x
  • 33
  • 7
  • What did you try already? Show us your efforts made, you have a regex defined, did you try to use that in the bash script? – Inian Jul 16 '18 at 07:39
  • 2
    Use `=~` and `BASH_REMATCH`. – Socowi Jul 16 '18 at 07:39
  • 4
    @ap3x: `bash` regex does not support `\d`, define your regex as `regex='^.*([[:digit:]]{1})\.([[:digit:]]{2})\.([[:digit:]]{4}).*$'` – Inian Jul 16 '18 at 08:00
  • Thank you for clarification, however the regexp does not work. – ap3x Jul 16 '18 at 08:09
  • @ap3x: `filename="xzxzxzxz4.12.3123fsfsfsfsfsfs"; [[ $filename =~ $regex ]] && echo ${BASH_REMATCH[1]}` – Inian Jul 16 '18 at 08:10
  • It seems to me there will be a problem with greediness. Try `regex='^(.*[^0-9])?([0-9]+\.[0-9]+\.[0-9]+)(.*)$'`. See [the **online Bash demo**](http://rextester.com/TNQSN13689) – Wiktor Stribiżew Jul 16 '18 at 08:11
  • @TomFenech That is the optimal solution to only extract the numbers, but judging by the original pattern, OP wants to actually split the input into what is before the number, the number itself, and the rest of the string. – Wiktor Stribiżew Jul 16 '18 at 08:22
  • The way I read it, I thought that the OP was only interested in the numbers but the code suggests otherwise. @ap3x could you clarify please? Do you want to use the part before/after the numbers, or just capture `4.12.3123` and discard the rest? – Tom Fenech Jul 16 '18 at 08:28
  • @TomFenech: My opinion was the individual numbers alone, so from my regex above, just use the values from 3 captured groups – Inian Jul 16 '18 at 08:31
  • @Tom Fenech Yes, i just want 4.12.3123. As why i did group other was for testing purposes. And re='[0-9]+\.[0-9]+\.[0-9]+' [[ $filename =~ $re ]] && printf '%s\n' "${BASH_REMATCH[@]}" works perfectly. Thank You. – ap3x Jul 16 '18 at 08:43
  • After you are satisfied with the answers and are satisfied enough time has elapsed, please take a look at: [What should I do when someone answers my question?](http://stackoverflow.com/help/someone-answers) – David C. Rankin Jul 16 '18 at 09:07

3 Answers3

2

The easiest way to work with regexes in Bash, in terms of consistency between Bash versions and escaping, is to put the regex into a single-quoted variable and then use it unquoted, as below:

re='[0-9]+\.[0-9]+\.[0-9]+'
[[ $filename =~ $re ]] && printf '%s\n' "${BASH_REMATCH[@]}"

The main issue with your approach were that you were using the "Perl-style" \d, so in fact you could make your code work with:

if [[ "$filename" =~ (.*)([0-9]+\.[0-9]+\.[0-9]+)(.*) ]]; then
  echo "${BASH_REMATCH[2]}"
fi

But this unnecessarily creates 3 capture groups, when you don't even need one. Note that I also changed . (any character) to \. (a literal .).

Tom Fenech
  • 72,334
  • 12
  • 107
  • 141
1

one way to extract:

 grep -oP '\d\.\d+\.\d+' <<<$xfilename
Kent
  • 189,393
  • 32
  • 233
  • 301
0

There is one more way

$ filename="xzxzxzxz4.12.3123fsfsfsfsfsfs"
$ awk '{ if (match($0, /[0-9].[0-9]+.[0-9]+/, m)) print m[0] }' <<< "$filename"
4.12.3123
Manish R
  • 2,312
  • 17
  • 13