在shell脚本中,“##”是什么意思?

9

在编写脚本时,我遇到了这个命令:

f=${file##*/}

我很好奇知道这行代码中的##是什么意思?

1个回答

24
在bash中,它会删去一个前缀模式。这里基本上是给你最后一个路径分隔符"/"后面的所有内容,通过贪婪地删除前缀"*/",其中包括任意数量的字符,后面紧跟着一个"/"。
pax> fspec=/path/to/some/file.txt ; echo ${fspec##*/}
file.txt

在这个上下文中,贪婪(Greedy)指尽可能地匹配。还有一种非贪婪的变体(匹配最小可能的序列),以及后缀的等效物:

pax> echo ${fspec#*/}    # non-greedy prefix removal
path/to/some/file.txt
pax> echo ${fspec%%/*}   # greedy suffix removal (no output)
pax> echo ${fspec%/*}    # non-greedy suffix removal
/path/to/some

##*/%/*大致相当于你从basenamedirname中获得的内容,但在bash中执行,因此您不必调用外部程序:

pax> basename ${fspec} ; dirname ${fspec}
file.txt
/path/to/some

就我所知,记住 ##%%#% 的不同效果的方法如下。它们是各种类型的“去除器”。

因为在数字之前通常有 #(如 #1),所以它删除开头的内容。同样,% 通常在数字之后出现(如 50%),因此它会删除末尾的内容。

然后唯一的区别就是贪婪/非贪婪方面。拥有更多相同字符(##%%)显然意味着你很贪心,否则你会分享它们 :-)


1
我相信在 Bash 之前,Korn shell 就有了这种符号;无论如何,在 Korn shell 中也可以使用它。 - Jonathan Leffler
请注意,%%/*并不完全替代dirname。如果您向dirname提供一个裸文件名,它会返回'.',而%%/*则返回未更改的名称。(在脚本中,这可能会导致创建具有文件名的目录,而不是识别当前目录已存在。) - William
有没有一种方法可以在一定程度上贪心?例如,假设我有以下内容:fspec=/path/to/some/file.txt,我想要以下输出:some/file.txt - A Merii
1
@AMerii:就我个人而言,我会说这些运算符不能实现。但是如果你提出问题,我相信会有其他方法得到一些不错的答案。例如:echo '/path/to/some/file.txt' | perl -pne 's?.*/([^/]*/[^/]*$)?\1?' :-) - paxdiablo
谢谢您的建议,我会创建一个新的问题:D - A Merii
这个答案是针对Bash的(因为问题被标记为Bash),但请注意,这些参数扩展功能在更广泛的范围内也是可用的(例如使用sh),因为它们是POSIX标准的一部分:https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html - Patrick Sanan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接