问题:
对于形如 someletters_12345_moreleters.ext
的文件名,我想提取其中的5位数字并将它们放入一个变量中。
明确一下细节,一个文件名的形式是若干个字符(不包含下划线),跟着一个五位的数字,数字两边都有一个下划线,最后跟着另一组若干个字符(不包含下划线)。我想要提取这个5位数字并将它存入一个变量中。
我非常感兴趣于完成这一目标的不同方法。
回答:
使用 cut 命令
number=$(echo 'someletters_12345_subsequentchars.ext' | cut -d'_' -f 2)
echo $number
cut
是一个文本处理工具,用于按指定分隔符截取文件中的字段。-d '_'
参数指定使用下划线字符 (_
) 作为字段分隔符。-f 2
参数表示提取第二个字段(字段索引从1开始计数)。
使用 awk 命令
number=$(echo 'someletters_12345_subsequentchars.ext' | awk -F'_' '{print $2}')
echo $number
-F'_'
参数指定了输入文本的分隔符为下划线字符 (_
),这意味着awk
将依据下划线来划分输入行中的字段。{print $2}
是awk
脚本的一部分,其中$2
表示输入行中的第二个字段(字段编号从1开始)。
使用 Shell 参数扩展
input="someletters_12345_subsequentchars.ext"
tmp=${input#*_}
number=${tmp%_*}
echo $number
tmp=${input#*_}
: 这是 bash 中的参数扩展操作,#
符号在这里用于删除从左边开始匹配的第一个_
及其左边的所有字符。所以,tmp
变量将被赋值为"12345_subsequentchars.ext"
,去掉了原字符串中从左开始的第一个_
及其之前的someletters
部分。number=${tmp%_*}
: 同样是 bash 的参数扩展操作,但这次%
符号用于删除从右边开始匹配的第一个_
及其右边的所有字符。因此,number
变量将被赋值为"12345"
,去掉了原字符串中从右开始的第一个_
及其之后的subsequentchars.ext
部分。
使用 tr 命令
number=$(echo "someletters_12345_subsequentchars.ext" | tr -cd '[[:digit:]]')
echo $number
tr
是一个强大的字符转换命令,常用于替换或删除字符。-c
参数代表 complement(补集),告诉tr
命令对指定字符集之外的字符进行操作。-d
参数代表 delete(删除),删除匹配到的字符。'[[:digit:]]'
是一个 POSIX 正则表达式的字符类,它匹配任何十进制数字(0-9)。
使用 grep 命令
number=$(echo "$filename" | grep -oE '[[:digit:]]{5}' | head -1)
echo $number
grep
是一个文本搜索工具,这里使用了-o
选项,它仅输出匹配到的模式而非整行内容。-E
选项表示使用扩展正则表达式(ERE)。'[[:digit:]]{5}'
是一个正则表达式,匹配连续的任意五个数字字符。- 因此,
grep
会找出$filename
中连续出现的任意五个数字,并只输出这些数字。 head
命令用于显示文件或流的前几行,默认情况下显示头10行,但这里使用了-1
选项,表示只显示第一行。
总结起来,第一行命令的目的是从变量 $filename
所代表的字符串中找到第一个连续的五位数字序列,并将它存入 number
变量中。
参考:
- stackoverflow question 428109
- man cut
- man awk
- man tr
- man grep
- 3.5.3 Shell Parameter Expansion
相关阅读: