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 inwhat you accept, and conservative in what you send.${MYSTRING##*in}
Be liberal in what you accept, and conservative inwhat 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
)
精彩评论