我想做下面的事情 -
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]}'])
尽管有一个专用的:r
ootname 修饰符来删除扩展:
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"
1
print -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
删除文件名后缀。.prop
printf
由于我们知道该数组仅包含以 结尾的字符串.prop
,因此第二行可以缩短为
printf '%s\n' "${names[@]%.*}"
这将删除数组中每个字符串中最后一个点(和点)之后的所有内容names
。
shell 并不真正使用正则表达式来匹配文件名。它是通过文件名通配模式完成的。正则表达式更常用于匹配文件中的文本。