Expression after last specific character

foo="/sdf/here/jfds"
bar="${foo##*/}"

Can anyone explain how the "${foo##*/}" expression works? I understand it will return the string after the last forward slash (i.e. jfds). However, I have no idea how it does or what this type of expression is called?


It is one of several shell features, generically called shell expansion. This particular expansion is called parameter expansion*.

You can think of this particular shell expansion form as a left-truncate string function. You must use the curly braces as shown (that is not optional)..

When you use only one #, it means left-truncate only the first occurrence of the pattern which follows (up to the closing }. When you use two ##, it means left-truncate all consecutive pattern-matches. The result of var="a/b/c"; echo ${var#*/} is b/c... echo ${var##*/} returns c.

There is a complementary right-truncate. It uses % instead of the #... (I "remember" which is which because # is like a bash comment; always on the left).

The * is treated as a bash wildcard expansion.

Here is a list of all shell expansions, presented in precedence order.

The order of expansions is:

1. brace expansion ... prefix{-,\,}postfix             # prefix-postfix prefix,postfix
                    .. {oct,hex,dec,bin}               # oct hex dec bin
                     . {a..b}{1..2}                    # a1 a2 b1 b2
                     . {1..04}                         # 01 02 03 04
                     . {01..4}                         # 01 02 03 04
                     . {1..9..2}                       # 1 3 5 7 9
                     . \$\'\\x{0..7}{{0..9},{A..F}}\'  # $'\x00' .. $'\x7F'     

2. tilde expansion .... ~           # $HOME
                    ... ~axiom      # $(dirname "$HOME")/axiom  
                    ... ~fred       # $(dirname "$HOME")/fred
                     .. ~+          # $PWD     (current working directory)
                     .. ~-          # $OLDPWD  (previous working directory. If OLDPWD is unset,
                                                        ~- is not expanded. ie. It stays as-is,
                                                          regardless of the state of nullglob.)
                                    # Expansion for Directories in Stack. ie. 
                                    # The list printed by 'dirs' when invoked without options 
                      . ~+N         #    Nth directory in 'dirs' list (from LHS)
                      . ~-N         #    Nth directory in 'dirs' list (from RHS)

3. parameter expansion .... ${VAR/b/-dd-}  
                        ... ${TEST_MODE:-0}
                         .. ${str: -3:2}  # note space after :
                          . ${#string}

4. (processed left-to-right) 
     variable expansion 
     arithmetic expansion
     command substitution

▶5. word splitting          # based on $IFS (Internal Field Seperator)

▷6. pathname expansion
      according to options such as:   
      nullglob, GLOBIGNORE, ...and more

# Note: ===============
▶ 5. word splitting     ↰ 
▷ 6. pathname expansion ↰  
# =====================  ↳  are not performed on words between  [[  and  ]]