Bash 正则表达式使用反向引用命名捕获组?

Bash 正则表达式使用反向引用命名捕获组?

我想做下面的事情 -

bash-shell>echo (*).prop ; echo \1 

显然上面的方法是行不通的。但想知道这是否可能以及等效的工作是什么。

我想要*(对于 shell 来说是通配符)匹配当前目录中的所有文件。当然,将上述搜索限制为仅以 .prop 结尾的文件。捕获不带 .prop 扩展名的文件名并使用反向引用打印它\1

我添加的示例有点简单只是为了解释。我的用例涉及更多,但我需要的是反向引用来满足我的要求。

答案1

ksh93 是唯一支持 AFAIK 中的反向引用的 shell,ksh93 和 zsh 支持捕获组,这更像是您在这里寻找的内容,但即使如此,您也无法按照您的建议使用它。 ( ksh93 \1) 或$match[1](zsh) 需要引用为每个匹配文件捕获的内容。

在 ksh93 中,您可以执行以下操作:

files=( ~(N)*.prop )
(( ${#files[@]} == 0 )) || printf '%s\n' "${files[@]/@(*).prop/\1}"

在 zsh 中:

set -o extendedglob
files=( *.prop(N) )
print -rC1 -- ${files/(#b)(*).prop/$match[1]}

作为操作符的一部分,对每个匹配文件完成对捕获组的引用${array/pattern/replacement}

对于zsh,这也可以作为 val glob 限定符的一部分来完成e

set -o extendedglob
print -rC1 -- *.prop(Ne['REPLY=${REPLY/(#b)(*).prop/$match[1]}'])

尽管有一个专用的:rootname 修饰符来删除扩展:

print -rC1 -- *.prop(N:r)

在 bash 中,你总是可以这样做:

shopt -s nullglob
files=( *.prop )
(( ${#files[@]} == 0 )) ||
  printf '%s\n' "${files[@]%.prop}"

反向引用是基本正则表达式和其他一些正则表达式引擎的一个功能。

bash确实有一个内置的正则表达式匹配运算符,但请注意它使用扩展正则表达式(ERE)。标准 ERE 不进行反向引用,尽管某些实现支持将其作为扩展。

在:

[[ aa =~ (.)\1 ]]

不太有效,因为\1不是标准 ERE 运算符,但因为 bash 将其\1视为带引号的1,因此调用系统的正则表达式引擎(.)1作为正则表达式。

regexp='(.)\1'
[[ aa =~ $regex ]]

可以在扩展正则表达式引擎支持反向引用的系统上工作,例如在 GNU 系统上。

在这里,它更多的是你想要的捕获,而 bash 确实做到了这一点。

成功后

[[ $file =~ ^(.*)\.prop$ ]]

匹配的内容将在(数组的第二个元素;在 zsh 中捕获的内容进入数组)(.*)中可用,因此您可以执行以下操作:${BASH_REMATCH[1]}$BASH_REMATCH$match

shopt -s nullglob
for file in *.prop; do
  if [[ $file =~ ^(.*)\.prop$ ]]; then
    printf '%s\n' "${BASH_REMATCH[1]}"
  fi
done

(请注意,可能会*.prop出现[[ $file =~ ^(.*)\.prop$ ]]失败的文件,例如文件名未在用户的区域设置字符集中编码时)。


无论如何,在 POSIX shell 中,与or\1相同,即带引号的。因此,旨在符合 POSIX 要求的 shell 只能在 POSIX 未指定的区域中赋予它不同的含义,例如在ksh93 中,以查找以两个相同字符开头的文件(其中未加引号的字符会产生未指定的行为),或者前面提到的文件不是POSIX 指定的运算符。'1'"1"1print -r -- @(?)\1*()"${files[@]/@(*).prop/\1}"${array/pattern/replacement}

答案2

使用 GNU basename(或basename在 FreeBSD 或任何其他实现上,为您提供非标准-a-s选项来处理多个单个参数并从每个参数中删除后缀):

basename -a -s .prop -- *.prop

这将为您提供与模式匹配的文件的名称*.prop,但.prop删除了文件名后缀。

使用类似于您建议的方式:

names=( *.prop )
printf '%s\n' "${names[@]%.prop}"

这将创建一个数组 ,names其中包含所有匹配的名称。 then使用的变量替换会在输出每个名称之前printf删除文件名后缀。.propprintf

由于我们知道该数组仅包含以 结尾的字符串.prop,因此第二行可以缩短为

printf '%s\n' "${names[@]%.*}"

这将删除数组中每个字符串中最后一个点(和点)之后的所有内容names

shell 并不真正使用正则表达式来匹配文件名。它是通过文件名通配模式完成的。正则表达式更常用于匹配文件中的文本。

相关内容