在 shell 参数扩展中保持匹配模式

xen*_*oid 4 bash variable-substitution

我可以使用${variable##pattern}(前导)或${variable%%pattern}(尾随)删除 bash 变量中的模式。

但是我找不到一种只使用 bash 的方法来保留模式并丢弃其余的。

我知道有使用sed,awk或 的解决方案grep,但我想知道是否有我忽略的合理有效的仅 bash 解决方案?

PS:这不仅仅是一个闲置的问题。最初的问题是我想处理名称包含模式(技术上,'[A-Z]+([A-Z])-[0-9][0-9]+([0-9])'大写字母后跟破折号和数字)的文件,我想使用相同的模式列出文件并提取匹配的字符串以进行进一步处理。

Qua*_*odo 7

${var%"${var##pattern}"}
${var#"${var%%pattern}"}
Run Code Online (Sandbox Code Playgroud)

例子:

$ k='ab*10cd20ef*'
$ echo "${k%"${k##*[0-9]}"}"
ab*10cd20
$ echo "${k#"${k%%[0-9]*}"}"
10cd20ef*
Run Code Online (Sandbox Code Playgroud)

请注意,引号对于防止 shell 将扩展解释为模式很重要。尝试echo "${k#${k%%[0-9]*}}"查看它输出不正确的结果。

  • 严格来说不是“`bash`-only”解决方案,因为它可以移植到所有类似`sh`的shell :-) (2认同)

ilk*_*chu 3

在 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
Run Code Online (Sandbox Code Playgroud)

使用file=foo-BAR-1234.txt,这将匹配零件BAR-1234并相应地打印。您还可以在正则表达式中使用括号来捕获模式的一部分,它们可以在${BASH_REMATCH[1]}等中使用。

当然,请注意,正则表达式的格式与 Bash/Ksh 扩展 glob 的格式不同:+([abc])您需要的是[abc]+、 或 ,而不是([abc])+,当星号仅应用于该一个括号组时,括号是可选的。对于*和也是如此?。另外,您可以写例如[0-9]{3,}三位或更多数字。