$ s=/the/path/foo.txt
我们可以通过不同的标准分别提取
$ echo ${s##*/}
foo.txt
$ echo ${s%.txt}
/the/path/foo
但如果我们想同时根据这两个标准进行提取,
$ echo ${${s##*/}%.txt}
bash: ${${s##*/}%.txt}: bad substitution
是否可以仅使用参数扩展而不引入临时变量来实现相同的目标?
参数扩展可以以某种方式在另一个参数扩展中工作吗?
谢谢。
答案1
不,又是。在 Bash 或标准 shell 中第一部分扩展必须是范围(即变量或位置参数,或特殊参数之一),而不仅仅是任何单词。
重击:
参数扩展的基本形式是${范围}。的价值范围被替换。这范围是如上所述的 shell 参数或数组引用。
这POSIX 中的文本同样只提到参数。
您可以使用扩展其他部分扩展,因为它们可以是任意单词。但这当然无助于同一字符串的链接操作(就像在您的示例中一样${${s##*/}%.txt}
)
$ bash -c 's=/the/path/foo.txt; ext=.tyt; echo "${s%${ext/y/x}}"'
/the/path/foo
Zsh 明确支持不过,链接:
如果使用 ${...} 类型参数表达式或 $(...) 类型命令替换来代替姓名上面,它首先被扩展,并且结果被使用,就好像它是姓名。
答案2
如果您正在寻找无扩展名文件名组件(即foo
)作为单个操作,您可以使用 RE 匹配从路径中提取它:
s=/the/path/foo.txt
[[ "$s" =~ (.*/)?(.*)\. ]]
echo "Got > ${BASH_REMATCH[2]} <" # "Got > foo <"
我还没有找到一种方法来从文件名中删除最短的未知扩展名,例如foo.bar.txt
同时仍然处理根本没有扩展名的文件名组件(例如foo
),除非您乐意接受复合表达式:
[[ "$s" =~ (.*/)?(.*)(\.[^.]*)$ ]] || [[ "$s" =~ (.*/)?(.*) ]]
如果你这样做,连续执行两次替换然后走开会更有效:
s=/path/to/foo
f=${s##*/}
echo "${f%.*}"