在 bash 中使用变量、大括号和散列字符的 ${0 # # ... }语法的意义是什么?

我只是在 bash 中看到了一些我不太懂的代码。作为新手的脚本,我不知道这是怎么回事。

echo ${0##/*}
echo ${0}

在这两个命令中,我实际上没有看到输出有什么不同(打印脚本名)。那个 #仅仅是一个评论吗?还有 /*是怎么回事。如果它是一个注释,为什么它不干扰关闭 }括号?

有人能告诉我一些关于这种语法的见解吗?

35013 次浏览

Linux 提示: Bash 参数和参数扩展

${PARAMETER##WORD}  Results in removal of the longest matching pattern from the beginning rather than the shortest.
for example
[ian@pinguino ~]$ x="a1 b1 c2 d2"
[ian@pinguino ~]$ echo ${x#*1}
b1 c2 d2
[ian@pinguino ~]$ echo ${x##*1}
c2 d2
[ian@pinguino ~]$ echo ${x%1*}
a1 b
[ian@pinguino ~]$ echo ${x%%1*}
a
[ian@pinguino ~]$ echo ${x/1/3}
a3 b1 c2 d2
[ian@pinguino ~]$ echo ${x//1/3}
a3 b3 c2 d2
[ian@pinguino ~]$ echo ${x//?1/z3}
z3 z3 c2 d2

请参阅 Bash 黑客维基的参数扩展页面上关于 子串删除的章节:

${PARAMETER#PATTERN}${PARAMETER##PATTERN}

这个表单是为了从字符串的开头删除试图匹配它的所描述的模式。操作符 #将尝试删除与模式匹配的最短文本,而 ##尝试删除与模式匹配的最长文本。

示例字符串(只是一个大人物的引用) :

MYSTRING="Be liberal in what you accept, and conservative in what you send"

语法 结果
${MYSTRING#*in} 在你接受的东西上要自由,在你发送的东西上要保守。
${MYSTRING##*in} 对于你接受的东西要自由,对于你发送的东西要保守。

我不敢相信我正在回答一个青少年的问题,但是我认为现有的答案(当然是准确的)错过了 OP 问题的实际要点。

观察员问道:

echo ${0##/*}

我猜他们在代码中真正看到的是:

echo ${0##*/}

后者本质上意味着“删除最后一个斜杠(如果有的话)之前的所有内容”。因此,这是一种简洁的方法,可以在不使用路径的情况下获得脚本的名称,而不管脚本是如何调用的。等于 *

basename "$0"

但是,如果您将它作为变量使用,而不是仅仅将它打印到控制台,那么它可能更方便(也更有效率)。(OTOH 基名更具可移植性,而参数扩展则是一种抨击。)

或多或少 * 。还有一些边缘情况(例如以空格开头的文件名) ,它们不会输出完全相同的内容。

你是说 ##/*还是 ##*/

##/*

${0##/*}有点不同寻常——它会从 $0的开头去掉前缀 /...

这是一个要么全有要么全无的操作: 如果 $0以斜杠开始(例如 /home/bob/myscript.sh) ,那么它将删除所有内容并返回一个空字符串。否则(例如 ./myscript.sh)它将什么也不剥离,并返回整个 $0

(双 ##表示它应该去掉最长的匹配; 如果是斜杠,单个 #只会去掉第一个字符。)

我不知道这有什么用。也许它可以用来帮助检测是否从绝对路径调用脚本。

##*/

${0##*/}更常见-它将从 $0开始。

例如,如果 $0/home/bob/myscript.sh,它将返回 myscript.sh

##再次指示它应该去掉最长的匹配项,因此它将去掉所有斜杠(.../.../)。
(与 #不同,#只会去掉第一个斜杠,例如 /home/bob/myscript.sh-> home/bob/myscript.sha/b/myscript.sh-> b/myscript.sh)