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

31,165

Solution 1

See the section on Substring removal in the Advanced Bash-Scripting Guide‡:

${string#substring}

Deletes shortest match of substring from front of $string.

${string##substring}

Deletes longest match of substring from front of $string.

The substring may include a wildcard *, matching everything. The expression ${0##/*} prints the value of $0 unless it starts with a forward slash, in which case it prints nothing.

‡ The guide, as of 3/7/2019, mistakenly claims that the match is of $substring, as if substring was the name of a variable. It's not: substring is just a pattern.

Solution 2

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

Solution 3

I can't believe I'm answering a teen-aged question, but 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.

Share:
31,165
user215997
Author by

user215997

Updated on July 05, 2022

Comments

  • user215997
    user215997 almost 2 years

    I just saw 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?

  • Benjamin W.
    Benjamin W. about 3 years
    Would you mind adding a link to the relevant section in the Bash reference manual to this? For example gnu.org/software/bash/manual/…
  • Muhammad Awais
    Muhammad Awais almost 3 years
    some explanation for beginners like me would have been better like how these patterns are working
  • tripleee
    tripleee about 2 years
    As also suggested by the footnote and the previous comment, the ABS is not a good canonical reference; this answer could be improved by citing authoritative or at least respected sources instead.
  • Charles Duffy
    Charles Duffy almost 2 years
    Consider the objections to linking the ABS reiterated; it teaches a lot of antipatterns and bad practices. Another good reference is wiki.bash-hackers.org/syntax/pe.