${variable##pattern}
我可以使用(前导)或(尾随)删除 bash 变量中的模式${variable%%pattern}
。
但我找不到一种仅 bash 的方法来保留模式并抛出其余的。
我知道有使用sed
、awk
、 或 的解决方案grep
,但我想知道是否有一个我忽略的相当有效的仅 bash 解决方案?
PS:这不仅仅是一个无聊的问题。最初的问题是我想处理名称包含模式的文件(从技术上讲,'[A-Z]+([A-Z])-[0-9][0-9]+([0-9])'
:大写字母后跟破折号和数字),并且我想使用相同的模式列出文件并提取匹配的字符串以进行进一步处理。
答案1
${var%"${var##pattern}"}
${var#"${var%%pattern}"}
例子:
$ k='ab*10cd20ef*'
$ echo "${k%"${k##*[0-9]}"}"
ab*10cd20
$ echo "${k#"${k%%[0-9]*}"}"
10cd20ef*
请注意,引号对于防止 shell 将扩展解释为模式很重要。尝试echo "${k#${k%%[0-9]*}}"
查看它输出的结果是否正确。
答案2
在 Bash 中,您还可以使用正则表达式:
#!/bin/bash
re='[A-Z][A-Z]+-[0-9][0-9][0-9]+'
file=foo-BAR-1234.txt
if [[ $file =~ $re ]]; then
echo "filename '$file' matches, matching part is '${BASH_REMATCH[0]}'"
fi
使用file=foo-BAR-1234.txt
,这将匹配零件BAR-1234
并相应地打印。您还可以在正则表达式中使用括号来捕获模式的一部分,它们可以在${BASH_REMATCH[1]}
等中使用。
当然,请注意,正则表达式的格式与 Bash/Ksh 扩展 glob 的格式不同:+([abc])
您需要的是[abc]+
、 或,而不是([abc])+
,当星号仅应用于该一个括号组时,括号是可选的。对于*
和 也是如此?
。另外,您可以写例如[0-9]{3,}
三位或更多数字。