英文:
zsh basename and ${var%.*}
问题
如何理解file2和file3之间的不同输出?
(base) ➜ Youtube cat 1.sh
base="/VS/Harry Potter - Hedwig's Theme (Harmonica Ver.) [w2kuM-Rp_IY].info.json"
echo "base: $base";
dir=$(dirname "$base");
filename=$(basename "$base");
file=${${filename%.*}%.*};
file2=${${"$(basename $filename)"%.*}%.*};
file3=${${$(basename $filename)%.*}%.*};
echo "file: $dir/$file";
echo "file2: $dir/$file2";
echo "file3: $dir/$file3";
(base) ➜ Youtube zsh 1.sh
base: /VS/Harry Potter - Hedwig's Theme (Harmonica Ver.) [w2kuM-Rp_IY].info.json
file: /VS/Harry Potter - Hedwig's Theme (Harmonica Ver.) [w2kuM-Rp_IY]
file2: /VS/Harry Potter - Hedwig's Theme (Harmonica Ver.) [w2kuM-Rp_IY]
file3: /VS/Harry Potter - Hedwig's Theme (Harmonica Ver [w2kuM-Rp_IY]
看起来basename命令返回由空格分割的多个部分,${var%.*}
命令在每个部分上起作用。
英文:
How to understand the different output between file2 and file3?
(base) ➜ Youtube cat 1.sh
base="/VS/Harry Potter - Hedwig's Theme (Harmonica Ver.) [w2kuM-Rp_IY].info.json"
echo "base: $base";
dir=$(dirname "$base");
filename=$(basename "$base");
file=${${filename%.*}%.*};
file2=${${"$(basename $filename)"%.*}%.*};
file3=${${$(basename $filename)%.*}%.*};
echo "file: $dir/$file";
echo "file2: $dir/$file2";
echo "file3: $dir/$file3";
(base) ➜ Youtube zsh 1.sh
base: /VS/Harry Potter - Hedwig's Theme (Harmonica Ver.) [w2kuM-Rp_IY].info.json
file: /VS/Harry Potter - Hedwig's Theme (Harmonica Ver.) [w2kuM-Rp_IY]
file2: /VS/Harry Potter - Hedwig's Theme (Harmonica Ver.) [w2kuM-Rp_IY]
file3: /VS/Harry Potter - Hedwig's Theme (Harmonica Ver [w2kuM-Rp_IY]
It seems basename command returns a serval part split by space and ${var%.*}
command works on each part.
答案1
得分: 1
>似乎basename命令返回由空格分隔的多个部分,${var%.*}
命令对每个部分都有效。
基本上是的。
根据命令替代文档:
>如果替代没有用双引号括起来,输出会使用IFS
参数分成单词。
以及关于模式删除和替代的参数扩展部分:
>... 当name是一个数组且替代没有用引号括起来,或者使用了(@)
标志或name[@]
语法时,匹配和替代会分别在每个数组元素上执行。
所以这就是你在未引用的命令替代中遇到的情况。其输出被拆分成单词,然后检查每个单词是否有匹配的模式要删除。
英文:
>It seems basename command returns a serval part split by space and ${var%.*}
command works on each part.
Pretty much, yes.
From the documentation on command substitution:
>If the substitution is not enclosed in double quotes, the output is broken into words using the IFS
parameter.
And from the section on parameter expansion talking about pattern deletion and substitutions:
>... when name is an array and the substitution is not quoted, or if the (@)
flag or the name[@]
syntax is used, matching and replacement is performed on each array element separately.
So that's the situation you're running into with the unquoted command substitution. Its output is broken up into words and each word is checked for a matching pattern to delete.
答案2
得分: 1
你没有引用 $( command substitution )
,所以它被 IFS
字符分割,并被后续嵌套的 ${}
参数扩展视为数组值。由于是数组值,${param%pattern}
扩展被应用于每个元素。然后,由于 file3=...
是标量赋值,结果被第一个 IFS
字符连接起来。这将发生在任何命令的输出上 - 这不是特定于 basename
。如果输入字符串包含多个类型的 IFS 字符或多个连续的 IFS 字符,则效果会更加明显。
在 zsh 中,您可以使用 t
(尾部)或 h
(头部)扩展修饰符,而不是外部的 basename
或 dirname
工具。
r
(根)修饰符似乎更适合您截取 "extension" 部分的用例:
base="/VS/Harry Potter - Hedwig's Theme (Harmonica Ver.) [w2kuM-Rp_IY].info.json"
file4=$base:r:r
typeset -p file4
它只作用于路径的尾部,因此您无需执行自己的拆分->修改->连接处理。file4=$base:F[2]r
是另一种选择,而不是将 :r
重复两次。这是 F:expr:
修饰符,用于重复以下的 r
修饰符 2 次。
英文:
You didn't quote the $( command substitution )
so it got split by IFS
characters and treated like an array value by subsequent nested ${}
parameter expansions. Being array valued, the ${param%pattern}
expansion was applied to each element. Then the result was joined by the first character of IFS
due to file3=...
being a scalar assignment. This would have happened to the output from any command - it is not specific to basename
. The effect would have been more noticeable had the input string contained >1 type of IFS character or >1 sequential IFS character.
In zsh you may use the t
(tail) or h
(head) expansion modifiers, rather than external basename
or dirname
tools.
The r
(root) modifier seems to be a better fit for your use case of chomping off the "extension" part:
base="/VS/Harry Potter - Hedwig's Theme (Harmonica Ver.) [w2kuM-Rp_IY].info.json"
file4=$base:r:r
typeset -p file4
It will only act on the tail of the path, so you don't need to do your own split->modify->join processing. file4=$base:F[2]r
is another option instead of doubling the :r
. That is the F:expr:
modifier to repeat the following r
modifier 2 times.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论