Cut string of numbers at letter in bash

Viewed 181

I have a string such as plantford1775.274.284b63.11.

I have been using identity=$( echo "$identity" | cut -d'.' -f3) to cut at each dot, and then choose the third section. I am left with 284b63.

The format of this part is always a letter, sandwiched by varying amounts of numbers. I would like to take the first few numbers before the letter. An example code line would be this:

identity=$( echo "$identity" | cut -d'anyletter' -f1)

What do I replace anyletter with to cut at whatever letter is listed there, so that I end with a string of 284?

7 Answers

This could be done in single awk, please try following written and tested with your shown samples.

echo "$identity" | awk -F'.' '{sub(/[^0-9].*/,"",$3);print $3}'

Explanation: simple explanation would be, passing echo command's output as a standard input to awk code. In awk program, setting field separator as . for values. Then in 3rd field substituting(using sub function of awk) everything apart from digits with NULL in 3rd field, then printing it.

Try:

echo plantford1775.274.284b63.11 | cut -d. -f3 | sed 's/[a-z].*//'

Or a slight variation on the REGEX, with [[...]] in bash:

v="plantford1775.274.284b63.11"
[[ $v =~ ^[^.]+.[^.]+.([^.]+).*$ ]] && echo ${BASH_REMATCH[1]}

Output

284b63

Or if you are only interested in the digits before the letter:

[[ $v =~ ^[^.]+.[^.]+.([[:digit:]]+)[^.]+.*$ ]] && echo ${BASH_REMATCH[1]}

Output

284

With bash, using the =~ operator :

[[ $identity =~ [^.]*.[^.]*.([0-9]+) ]] && identity=${BASH_REMATCH[1]}

or, in POSIX shell:

identity=${identity#*.*.}
identity=${identity%%[^0-9]*}

or, using sed:

identity=$(sed 's/[^.]*.[^.]*.\([0-9]*\).*/\1/' <<< "$identity")

Maybe you can use a bash regex and get the result from $BASH_REMATCH.

[[ "$identity" =~ ([0-9]+)[a-z][0-9]+ ]] && identity="${BASH_REMATCH[1]}"

Say we have

 identity=284b63

then you can do a

 lead=${identity%[a-z]*}

to set lead to 284. Feel free to adapt the pattern to upper case letters and/or other separators.

If the format of this part is always a letter, sandwiched by varying amounts of numbers, and you want to match this format, you might also use gnu awk, setting the field separator to . and use a pattern with a capture group for the 3rd field.

The pattern captures 1 or more digits from the start of the string, and match one of more chars [a-z] after it followed by a digit.

echo "$identity" | awk -F'.' 'match($3, /^([0-9]+)[a-z]+[0-9]/, ary) {print ary[1]}'

Output

284

Or using sed with a pattern matching the first 2 dots and the capture group after the 2nd dot:

identity=$(sed 's/^[^.]\+\.[^\.]\+\.\([0-9]\+\)[a-z]\+[0-9].*/\1/' <<< "$identity")
Related