给定someletters_12345_moreleters形式的文件名。ext,我想提取5位数字,并将它们放入一个变量。
为了强调这一点,我有一个x个字符的文件名,然后是一个5位数字序列,两边都有一个下划线,然后是另一组x个字符。我想把这个5位数代入一个变量。
我对实现这一目标的多种不同方式非常感兴趣。
给定someletters_12345_moreleters形式的文件名。ext,我想提取5位数字,并将它们放入一个变量。
为了强调这一点,我有一个x个字符的文件名,然后是一个5位数字序列,两边都有一个下划线,然后是另一组x个字符。我想把这个5位数代入一个变量。
我对实现这一目标的多种不同方式非常感兴趣。
当前回答
bash解决方案:
IFS="_" read -r x digs x <<<'someletters_12345_moreleters.ext'
这将破坏一个名为x的变量。var x可以被更改为var _。
input='someletters_12345_moreleters.ext'
IFS="_" read -r _ digs _ <<<"$input"
其他回答
以下是我的做法:
FN=someletters_12345_moreleters.ext
[[ ${FN} =~ _([[:digit:]]{5})_ ]] && NUM=${BASH_REMATCH[1]}
解释:
Bash-specific:
[[]]为条件表达式 =~表示条件为正则表达式 如果前一个命令成功,&&将链接这些命令
正则表达式(RE): _([[:digit:]]{5})_
_是字面量,用于为被匹配的字符串划分/锚定匹配边界 ()创建捕获组 [[:digit:]]是一个字符类,我认为它不言自明 {5}表示前面的字符中的恰好五个,类(如本例中所示)或组必须匹配
In english, you can think of it behaving like this: the FN string is iterated character by character until we see an _ at which point the capture group is opened and we attempt to match five digits. If that matching is successful to this point, the capture group saves the five digits traversed. If the next character is an _, the condition is successful, the capture group is made available in BASH_REMATCH, and the next NUM= statement can execute. If any part of the matching fails, saved details are disposed of and character by character processing continues after the _. e.g. if FN where _1 _12 _123 _1234 _12345_, there would be four false starts before it found a match.
如果我们关注以下概念: 一串(一个或几个)数字。
我们可以使用一些外部工具来提取这些数字。 我们可以很容易地擦除所有其他字符,无论是sed还是tr:
name='someletters_12345_moreleters.ext'
echo $name | sed 's/[^0-9]*//g' # 12345
echo $name | tr -c -d 0-9 # 12345
但如果$name包含几组数字,则上述操作将失败:
如果“name = someletters_12345_moreleters_323_end。ext”,那么:
echo $name | sed 's/[^0-9]*//g' # 12345323
echo $name | tr -c -d 0-9 # 12345323
我们需要使用正则表达式。 在sed和perl中只选择第一次运行(12345而不是323):
echo $name | sed 's/[^0-9]*\([0-9]\{1,\}\).*$/\1/'
perl -e 'my $name='$name';my ($num)=$name=~/(\d+)/;print "$num\n";'
但我们也可以直接在bash(1)中执行:
regex=[^0-9]*([0-9]{1,}).*$; \
[[ $name =~ $regex ]] && echo ${BASH_REMATCH[1]}
这允许我们提取任意长度的数字的第一行 被其他文本/字符包围。
注意:正则表达式=[^ 0 - 9]*([0 - 9]{5,5})。*美元;将只匹配精确的5位数运行。:-)
(1):每段短文本都比调用外部工具快。并不比在sed或awk中处理大文件快。
bash解决方案:
IFS="_" read -r x digs x <<<'someletters_12345_moreleters.ext'
这将破坏一个名为x的变量。var x可以被更改为var _。
input='someletters_12345_moreleters.ext'
IFS="_" read -r _ digs _ <<<"$input"
遵循要求
我有一个文件名,x个字符,然后是5位数字 序列两侧分别用一个下划线包围 x个字符的集合。我想取一个5位数 把它代入一个变量。
我发现了一些可能有用的grep方法:
$ echo "someletters_12345_moreleters.ext" | grep -Eo "[[:digit:]]+"
12345
或更好的
$ echo "someletters_12345_moreleters.ext" | grep -Eo "[[:digit:]]{5}"
12345
然后使用-Po语法:
$ echo "someletters_12345_moreleters.ext" | grep -Po '(?<=_)\d+'
12345
或者如果你想让它正好适合5个字符:
$ echo "someletters_12345_moreleters.ext" | grep -Po '(?<=_)\d{5}'
12345
最后,要将它存储在一个变量中,只需要使用var=$(命令)语法。
还有bash内置的'expr'命令:
INPUT="someletters_12345_moreleters.ext"
SUBSTRING=`expr match "$INPUT" '.*_\([[:digit:]]*\)_.*' `
echo $SUBSTRING