开发者

What is the meaning of the ${0##...} syntax with variable, braces and hash character in bash?

I just saw开发者_C百科 some code in bash that I didn't quite understand. Being the newbie bash scripter, I'm not sure what's going on.

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

I don't really see a difference in output in these two commands (prints the script name). Is that # just a comment? And what's with the /*. If it is a comment, how come it doesn't interfere with the closing } brace?

Can anyone give me some insight into this syntax?


See the section on Substring removal on the parameter expansion page of the bash-hackers' wiki:

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

This form is to remove the described pattern trying to match it from the beginning of the string. The operator # will try to remove the shortest text matching the pattern, while ## tries to do it with the longest text matching.

Example string (just a quote from a big man):

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

Syntax Result
${MYSTRING#*in} Be liberal in what you accept, and conservative in what you send.
${MYSTRING##*in} Be liberal in what you accept, and conservative in what you send.


Linux tip: Bash parameters and parameter expansions

${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


I think the existing answers (while certainly accurate) miss the practical thrust of the OP's question.

The OP asked about:

echo ${0##/*}

My guess is that what they really saw in the code was:

echo ${0##*/}

The latter essentially means "delete everything up to, and including, the last slash (if any)". So it's a concise way of getting the name of the script without the path, regardless of how the script was called. It's equivalent* to

basename "$0"

but is arguably handier (and more efficient) if you're using it as a variable rather than just printing it to the console. (OTOH basename is more portable, whereas the parameter expansion is a bashism.)

* More or less. There are edge cases (such as file names that start with a space) where they don't output exactly the same thing.


Did you mean ##/*, or ##*/?

##/*

${0##/*} is a bit unusual - it will strip off the prefix /... from the start of $0.

It's an all-or-nothing operation: If $0 starts with a slash (e.g. /home/bob/myscript.sh), then it will strip everything and return an empty string. Otherwise (e.g. ./myscript.sh) it will strip nothing and return the the whole of $0.

(The double ## indicates that it should strip the longest match; a single # would only strip the first character, if it's a slash.)

I'm not sure how useful it is. Perhaps it could be used to help detect if a script is called from an absolute path or not.

##*/

${0##*/} is more common - it will will strip off the prefix .../ from the start of $0.

e.g. if $0 is /home/bob/myscript.sh, it will return myscript.sh.

The ## again indicates that it should strip the longest match, so it will strip all slashes (.../.../).
(As opposed to a #, which will strip the first slash only, e.g. /home/bob/myscript.sh -> home/bob/myscript.sh, a/b/myscript.sh -> b/myscript.sh)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜