给定someletters_12345_moreleters形式的文件名。ext,我想提取5位数字,并将它们放入一个变量。

为了强调这一点,我有一个x个字符的文件名,然后是一个5位数字序列,两边都有一个下划线,然后是另一组x个字符。我想把这个5位数代入一个变量。

我对实现这一目标的多种不同方式非常感兴趣。


当前回答

您可以使用参数展开来做到这一点。

如果a为常数,则下面的参数展开执行子字符串提取:

b=${a:12:5}

12是偏移量(从零开始),5是长度

如果数字周围的下划线是输入中唯一的下划线,您可以分两步分别去掉前缀和后缀:

tmp=${a#*_}   # remove prefix ending in "_"
b=${tmp%_*}   # remove suffix starting with "_"

如果有其他下划线,那么无论如何都可能是可行的,尽管比较棘手。如果有人知道如何在一个表达式中执行两个展开,我也想知道。

提出的两个解决方案都是纯bash,不涉及进程生成,因此非常快。

其他回答

有点晚了,但我刚刚遇到了这个问题,并发现了以下内容:

host:/tmp$ asd=someletters_12345_moreleters.ext 
host:/tmp$ echo `expr $asd : '.*_\(.*\)_'`
12345
host:/tmp$ 

我用它在一个没有%N日期的嵌入式系统上获得毫秒分辨率:

set `grep "now at" /proc/timer_list`
nano=$3
fraction=`expr $nano : '.*\(...\)......'`
$debug nano is $nano, fraction is $fraction

也许这可以帮助你得到想要的输出

代码:

your_number=$(echo "someletters_12345_moreleters.ext" | grep -E -o '[0-9]{5}')
echo $your_number

输出:

12345

通用解决方案,其中数字可以在文件名中的任何位置,使用这样的序列中的第一个:

number=$(echo $filename | egrep -o '[[:digit:]]{5}' | head -n1)

另一个精确提取变量一部分的解决方案:

number=${filename:offset:length}

如果你的文件名总是使用stuff_digits_…你可以使用awk:

number=$(echo $filename | awk -F _ '{ print $2 }')

还有一种方法可以删除除数字以外的所有内容,使用

number=$(echo $filename | tr -cd '[[:digit:]]')

使用sed replace的简单方法:

result=$(echo "someletters_12345_moreleters.ext" | sed 's/.*_\(.*\)_.*/\1/g')
echo $result

基于jor的回答(这对我来说并不适用):

substring=$(expr "$filename" : '.*_\([^_]*\)_.*')