如何获取与“*”通配符匹配的文件名的子字符串?

如何获取与“*”通配符匹配的文件名的子字符串?

假设我有一个包含以下文件(以及其他文件)的目录:

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

相关内容