根据bash脚本中的模式提取字符串


17

在bash中,假设我有一个字符串strname

strname="ph7go04325r"

我想提取第一个 "3"字符和最后一个 字符之间的"r"字符strname,并将结果保存在字符串中strresult。在上面的示例中,结果strresult将是:

strresult="25"

第一"3"字符是必然在串8位strname; 同样地,最后一个"r"必然在串位置11。因此,下面的两个串的strname应产生strresult="25"

strname="ph11go04325raa"
strname="325r"
strname="rgo04325raa"

另外,strname=ph12go04330raa"应屈服strresult="30"

我是bash脚本的新手,而且我不知道从哪里开始像这样进行字符串模式匹配。你有什么建议吗?

Answers:


28

您可以在bash(3.0或更高版本)中使用正则表达式来完成此操作:

if [[ $strname =~ 3(.+)r ]]; then
    strresult=${BASH_REMATCH[1]}
else
    echo "unable to parse string $strname"
fi

在bash中,来自正则表达式的捕获组被放置在特殊数组中BASH_REMATCH。元素0包含整个匹配项,元素1包含第一个捕获组的匹配项。


10

使用标准sh语法(因此可以与任何版本bash或任何其他POSIX兼容外壳一起使用),您可以执行以下操作:

case $strname in
  (*3*r*) 
    strresult=${strname#*3}
    strresult=${strresult%r*};;
  (*)
    printf >&2 '%s\n' "Unable to parse string $strname"
esac

另请参见expr即使在35岁的Unices上也可以使用的旧解决方案:

expr "x$strname" : 'x[^3]*3\(.*\)r'

旧的怪癖expr是,如果匹配失败你会得到一个非零退出状态(罚款),但你也可以得到一个非零退出状态,如果返回的字符串解析为0(像strname=zz300rzz)。


我认为您的措词有误,这意味着只能使用较旧版本的bash才能完成。当然,在现代shell中,参数扩展仍然是一种很好的方法。
kojiro

1
@kojiro,我明白你的意思了。最初的提法是对约旦的回答进行跟进。我已经更新了答案。
斯特凡Chazelas
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.