我需要在shell脚本中提取字符串的一部分。原始字符串非常复杂,所以我真的需要一个正则表达式来选择原始字符串的正确部分——仅仅删除前缀和后缀是行不通的。此外,正则表达式需要检查我想要提取的字符串的上下文,所以我需要一个正则表达式a([^b]*)b
从12a123b23
中提取123
。
shell脚本需要是可移植的,所以我不能使用Bash结构[[
和BASH_REMATCH
。
我希望脚本是健壮的,所以当正则表达式不匹配时,脚本应该注意到这一点,例如通过要使用的命令的非零退出代码。
做这件事的好方法是什么?
我尝试了各种工具,但没有一个能完全解决问题:
-
expr match "$original" ".*$regex.*"
除错误情况外有效。使用这个命令,我不知道如何检测正则表达式是否不匹配。此外,expr似乎使用提取的字符串来确定其退出代码—因此,当我碰巧提取00
时,expr的退出代码为1。所以我通常需要忽略expr match "$original" ".*$regex.*" || true
的退出代码除错误情况外, echo "$original" | sed "s/.*$regex.*/\1/"
也有效。为了处理这种情况,我需要测试是否返回了原始字符串,这也相当不美观。
那么,没有更好的方法来做到这一点吗?
您可以使用sed
的-n
选项来抑制所有输入行的输出,并将p
选项添加到替换命令中,如下所示:
echo "$original" | sed -n -e "s/.*$regex.*/1/p"
如果正则表达式匹配,则与前面一样打印匹配的组。但是现在,如果正则表达式不匹配,则不会打印任何内容,您只需要测试空字符串。
grep -o
怎么样?唯一可能的问题是可移植性,否则它满足所有要求:
➜ echo "hello and other things" | grep -o hello
hello
➜ echo $?
0
➜ echo "hello and other things" | grep -o nothello
➜ echo $?
1
最好的事情之一是,由于它是grep,您可以选择您想要的正则表达式,无论是BRE, ERE还是Perl。
如果egrep可用(几乎所有时间)
egrep 'YourPattern' YourFile
或
egrep "${YourPattern}" YourFile
如果只有grep可用
grep -e 'YourPattern' YourFile
您使用经典的[ $? -eq 0 ]
检查命令的状态(也考虑到坏的YourFile访问)
对于内容本身,使用sed或awk提取(为了可移植性问题)(在失败测试之后)
Content="$( sed -n -e "s/.*(${YourPattern}).*/1/p;q" )"