我目前正在尝试了解参数扩展,尤其是可以通过模式匹配删除部分参数值的不同形式。为了这个问题,让我们关注${parameter#word}
扩展。
手册中的两个相关部分(man bash
)(强调我的):
${parameter#word}
${parameter##word}
移除匹配的前缀模式。单词被扩展以产生一个模式,就像在路径名扩展中一样,并使用下面的模式匹配中描述的规则与参数的扩展值匹配。如果模式匹配参数值的开头,则扩展的结果是 删除了最短匹配模式('#'
案例)或最长匹配模式(案例)的参数扩展值。'##'
[...]
路径名扩展
分词后,除非设置了 -f 选项,否则 bash 会扫描每个单词中的字符 *、? 和 [。如果出现这些字符之一,则该单词被视为一个模式,并替换为按字母顺序排列的与该模式匹配的文件名列表(请参阅下面的模式匹配)。[...]
但是,请考虑终端会话的以下部分:
root@cerberus ~/scripts # mkdir test
root@cerberus ~/scripts # cd test
root@cerberus ~/scripts/test # touch foo
root@cerberus ~/scripts/test # String=foobar
root@cerberus ~/scripts/test # printf '%s\n' ${String#foo}
bar
root@cerberus ~/scripts/test # printf '%s\n' ${String#*}
foobar
root@cerberus ~/scripts/test #
我无法理解最后一个命令之后的输出。根据手册,*
应该扩展为foo
,因为foo
是当前目录中的唯一文件;至少,这是我的“像路径名扩展一样产生模式”的概念。
因此,在这种情况下,printf '%s\n' ${String#*}
应该给出与 相同的输出printf '%s\n' ${String#foo}
。
显然,事实并非如此。我的误解在哪里?
关于模式匹配:
并且,在子字符串删除的参数扩展中,
#
匹配最短,而##
最长匹配。这是从开头删除空字符串(最短匹配):
这是
foobar
从一开始就删除(最长匹配):关于您描述的最后一段:带有参数扩展的子字符串删除与当前目录中的文件无关。模式匹配参数值,而不是任何文件,将其视为对参数值的文本处理操作。
它将“单词”部分作为用于文件名生成的模式,但它不使用它来生成文件名。相反,那里的模式用于匹配给定参数的值。
例如,如果您有
str=foobsar
,那么将在 的开头${str#*o}
尝试模式,找到最短匹配项(匹配任意数量的任意字符),将其删除并扩展为. 同样会找到最长的匹配项,在 expand 处将其删除。*o
foobar
fo
*
obar
${str#*o}
foo
bar
它说“单词被扩展”的原因是您可以在“单词”部分使用扩展,如下所示:
或者
再说一次,在上面没有引用扩展的情况下,去除前缀后的结果将经历分词和通配。您可能应该引用整个扩展来防止这种情况,即 ie
"${str#*o}"
或其他。