如何在bash中查找字符串中的最后一个分组数字

时间:2018-08-20 15:26:04

标签: bash

这是this问题的后续问题,涉及如何知道字符串中分组数字的数量。

在bash中,

如何找到字符串中最后出现的一组数字? 所以,如果我有

string="123 abc 456"

我会得到

456

如果我有

string="123 123 456"

我仍然会得到

456

7 个答案:

答案 0 :(得分:2)

没有外部实用程序(例如sedawk...):

$ s="123 abc 456"
$ [[ $s =~ ([0-9]+)[^0-9]*$ ]] && echo "${BASH_REMATCH[1]}"
456

BASH_REMATCH是一个特殊的数组,其中[[ ... =~ ... ]]中的匹配项被分配给该数组。


测试代码:

str=("123 abc 456" "123 123 456" "123 456 abc def" "123 abc" "abc 123" "123abc456def")

for s in "${str[@]}"; do
    [[ $s =~ ([0-9]+)[^0-9]*$ ]] && echo "$s -> ${BASH_REMATCH[1]}"
done

输出:

123 abc 456 -> 456
123 123 456 -> 456
123 456 abc def -> 456
123 abc -> 123
abc 123 -> 123
123abc456def -> 456

答案 1 :(得分:1)

 grep -o '[0-9]\+' file|tail -1
  • grep -o仅列出匹配的文本
  • tail -1仅输出最后一个匹配项

好吧,如果您有字符串:

grep -o '[0-9]\+' <<< '123 foo 456 bar' |tail -1

答案 2 :(得分:1)

您可以在Bash中使用正则表达式:

$ echo "$string"
123 abc 456
$ [[ $line =~ (^.*[ ]+|^)([[:digit:]]+) ]] && echo "${BASH_REMATCH[2]}"
456

如果您要捕获456abc123def456之类的无界字符串,则可以执行以下操作:

$ echo "$string"
test456text
$ [[ $string =~ ([[:digit:]]+)[^[:digit:]]*$ ]] && echo "${BASH_REMATCH[1]}"
456

但是,如果您要使用外部工具,请使用awk

这里是Bash vs Awk的演示,以获取字符串中的最后一位数字。这些用于带有' '分隔符的数字,或者用于字符串的结尾或开头的数字。

给出:

$ cat file
456
123 abc 456
123 123 456
abc 456
456 abc
123 456 foo bar
abc123def456

这是一个测试脚本:

while IFS= read -r line || [[ -n $line ]]; do
    bv=""
    av=""
    [[ $line =~ (^.*[ ]+|^)([[:digit:]]+) ]] && bv="${BASH_REMATCH[2]}"
    av=$(awk  '{for (i=1;i<=NF;i++) if (match($i, /^[[:digit:]]+$/)) last=$i; print last}' <<< "$line")
    printf "line=%22s bash=\"%s\" awk=\"%s\"\n" "\"$line\"" "$bv" "$av"
done <file

打印:

line=                 "456" bash="456" awk="456"
line=         "123 abc 456" bash="456" awk="456"
line=         "123 123 456" bash="456" awk="456"
line=             "abc 456" bash="456" awk="456"
line=             "456 abc" bash="456" awk="456"
line=     "123 456 foo bar" bash="456" awk="456"
line=        "abc123def456" bash="" awk=""

答案 3 :(得分:1)

您可以使用此sed提取一行中的最后一个数字:

sed -E 's/(.*[^0-9]|^)([0-9]+).*/\2/'

示例:

sed -E 's/(.*[^0-9]|^)([0-9]+).*/\2/' <<< '123 abc 456'
456

sed -E 's/(.*[^0-9]|^)([0-9]+).*/\2/' <<< '123 456 foo bar'
456

sed -E 's/(.*[^0-9]|^)([0-9]+).*/\2/' <<< '123 123 456'
456

sed -E 's/(.*[^0-9]|^)([0-9]+).*/\2/' <<< '123 x'
123

RegEx详细信息:

  • (.*[^0-9]|^):开头匹配0个或更多字符,然后以非数字或行开头。
  • ([0-9]+):匹配1个以上的数字并捕获到#2组
  • .*:匹配其余字符直到行尾
  • \2:将其替换为后向引用2(我们在组2中捕获的内容)

答案 4 :(得分:1)

使用纯Bash的另一种方法:

shopt -s extglob            # enable extended globbing - for *(...)

tmp=${string%%*([^0-9])}    # remove non-digits at the end
last_digits=${tmp##*[^0-9]} # remove everything up to the last non-digit

printf '%s\n' "$last_digits"

答案 5 :(得分:0)

这是参数扩展的好工作:

$ string="123 abc 456"
$ echo ${string##* }
456

答案 6 :(得分:0)

一个简单的答案gawk

echo "$string" | gawk -v RS=" " '/^[[:digit:]]+$/ { N = $0 } ; END { print N }'

使用RS=" ",我们将每个字段作为单独的记录读取。 然后我们保留找到的最后一个数字并打印出来。

$ string="123 abc 456 abc"
$ echo "$string" | gawk -v RS=" " '/^[[:digit:]]+$/ { N = $0 } ; END { print N }'
456