Phocs
Phocs

Reputation: 2510

How can I get the last number from string in bash?

Sorry, I'll explain it better

How can I get the last number from string?

Examples of generics strings:

If str=str1s2
echo $str | cmd? 
I get 2

If str=234ef85
echo $str | cmd? 
I get 85

 If str=djfs1d2.3
echo $str | cmd? 
I get 3

"cmd?" is the command/script that I want

Upvotes: 15

Views: 20959

Answers (8)

PageFault
PageFault

Reputation: 41

Just found an efficient way to do this in pure Bash with no pipes or explicit conditionals:

# ##            Erase all occurrences of pattern from beginning of string:
# *             Absolutely anything
# [![:digit:]]  Single non-digit character

num="${str##*[![:digit:]]}"

Upvotes: 2

user1934428
user1934428

Reputation: 22225

No need to spawn a child process, since you have regexp matching in bash. Assume for example the string

str=a34b56c

Now you can do

if [[ $str =~ ([0-9]+)[^0-9]*$ ]]
then
  echo The last number is ${BASH_REMATCH[1]}
else
  echo The string "$str" does not contain digits
fi

The trick here is putting parenthesis around that part of the pattern which makes up the number. This allows you to pick up the number using ${BASH_REMATCH[1]}.

Upvotes: 1

Vojtech Vitek - golang.cz
Vojtech Vitek - golang.cz

Reputation: 27726

Get all numbers from a string:

grep -Eo '[0-9]+'

Get last number from a string:

grep -Eo '[0-9]+' | tail -1

(Expanding on George's answer a bit..)

  • -E means extended regex
  • -o means print each matching part on a separate line

Upvotes: 3

RomanPerekhrest
RomanPerekhrest

Reputation: 92854

Short gawk approach (for multiple variables):

echo "$str1 $str2 $str3 $str4 " | awk -v FPAT="[0-9]+ " '{for(i=1;i<=NF;i++) print "str"i": "$i}'

The output:

str1: 2 
str2: 3 
str3: 45 
str4: 8 

  • FPAT="[0-9]+ " - a regexp that matches the fields, instead of matching the field separator

As you have changed your initial condition:
For one single string it would be even simpler:

echo djfs1d2.3 | awk -v FPAT="[0-9]+" '{print $NF}'
3

Upvotes: 2

Walter A
Walter A

Reputation: 19982

You can use grep with

rev <<< "$str" | grep -Eo "[0-9]*" | head -1 |rev

EDIT: rev is not needed when I use tail -1 but the head/tail are overdone when you just add the end-of-line marker $ like @Vasiliou did (I upvoted his answer). Without rev and head the grep solution is better than sed. I deleted my remark "Better is using sed".

sed -r 's/.*[^0-9]+([0-9]*)$/\1/' <<< "$str" 

Upvotes: 4

George Vasiliou
George Vasiliou

Reputation: 6335

All you need is grep -Eo '[0-9]+$' :

gv@debian:~$ echo 234ef85 |grep -Eo '[0-9]+$'          ## --> 85
gv@debian:~$ echo 234ef856 |grep -Eo '[0-9]+$'         ## --> 856
gv@debian:~$ echo 234ef85d6 |grep -Eo '[0-9]+$'        ## --> 6
gv@debian:~$ echo 234ef85d.6 |grep -Eo '[0-9]+$'       ## --> 6
gv@debian:~$ echo 234ef85d.6. |grep -Eo '[0-9]+$'      ## --> no result
gv@debian:~$ echo 234ef85d.6.1 |grep -Eo '[0-9]+$'     ## --> 1
gv@debian:~$ echo 234ef85d.6.1222 |grep -Eo '[0-9]+$'  ## --> 1222

Upvotes: 19

choroba
choroba

Reputation: 241808

You can use parameter expansion with extglob. First, remove the number from the end, then remove what you got from the beginning.

#!/bin/bash
shopt -s extglob
for str in str1s2 djfs1d2.3 fefwfw4rfe45 234ef8 ; do
    without_number=${str%%+([0-9])}
    echo ${str#$without_number}
done

Upvotes: 9

Petr Skocik
Petr Skocik

Reputation: 60058

With awk:

INPUT:

 str1 = "str1s2"
 str2 = "djfs1d2.3"
 str3 = "fefwfw4rfe45"
 str4 = "234ef8"

command:

tr = \  < INPUT  |
awk '{ match($2,"[0-9]*\"$"); 
       printf "%s: %s\n", $1, substr($2,RSTART,RLENGTH-1);  }'

output:

str1: 2
str2: 3
str3: 45
str4: 8

Upvotes: 3

Related Questions