假设我有一个包含以下文件(以及其他文件)的目录:
touch doc-mike.txt doc-jane.txt doc-susan.txt
我可以使用以下结构在脚本中对这些文件执行某些操作:
for fname in doc-*.txt; do
echo input: ${fname}
done
但是,如果我想获取与通配符匹配的文件名的子字符串,我必须跳过一些丑陋的圈子:
for fname in doc-*.txt; do
wildcard=${fname#doc-}
wildcard=${wildcard%.txt}
echo input: ${fname} output: output-${wildcard}.results
done
这样可行:
input: doc-jane.txt output: output-jane.results
input: doc-mike.txt output: output-mike.results
input: doc-susan.txt output: output-susan.results
但我觉得必须有一种更好/更简单的方法来获取与"*"
glob 通配符匹配的子字符串
答案1
我能想到的最接近的是BASH_REMATCH
,因为 bash 将正则表达式文本的结果存储在该变量中:
$ for fname in doc-*.txt; do
[[ $fname =~ doc-(.*).txt ]];
echo "input: ${fname} output: output-${BASH_REMATCH[1]}.results";
done
input: doc-jane.txt output: output-jane.results
input: doc-mike.txt output: output-mike.results
input: doc-susan.txt output: output-susan.results
正如(.*)
正则表达式中的第一组一样,它位于BASH_REMATCH[1]
.我认为这是您想要的行为,但是对于 glob,我认为 bash 无法以任何方式实现这一点。
答案2
您zsh
可以混合使用glob 限定符、历史扩展修饰符和 globbing 标志去做吧。
假设您已通过以下方式启用了扩展通配符和历史模式替换模式
setopt extendedglob
setopt histsubstpattern
然后你可以运行
print doc-*.txt(#q:s/(#b)doc-(*).txt/'${match[1]}'/)
这将输出
jane mike susan
像往常一样,您可以将其与其他限定符/修饰符/标志结合使用,例如仅选择常规文件、将表达式锚定到单词的开头/结尾等。
不过,如果您想迭代每个文件名,则zsh
可以嵌套参数扩展,以便您的代码可以简化为
for fname in doc-*.txt; do
print input: ${fname} output: output-${${fname#doc-}%.txt}.results
done
以上(回复:你的评论) 使用单个表达式,不需要中间变量。
答案3
你也可以尝试
for fname in doc-*.txt; do
echo "input: ${fname} output: output-${fname:4:$((${#fname}-8))}.results"
done