Search code examples
bashshellparameter-expansion

Why does ${##parameter} always return 0?


Suppose that parameter=value is an internal variable in bash. When I try ${#parameter} in bash it returns a 5. But when I try, for instance, ${##parameter} or ${###parameter} it always give back 0 in return. Why it does not say that it is a substitution error as in other cases?


Solution

  • Short version

    You could express ${##parameter} as:

    x=$#
    ${x#parameter}
    

    and ${###parameter} as:

    x=$#
    ${x##parameter}
    

    You are performing a prefix removal on $# (number of arguments passed to a script / function).


    Longer version

    If parameter has any special meaning, it would be likely specific to your environment.

    $ echo \""${parameter}"\"
    ""
    

    or even:

    $ set -u
    $ echo \""${parameter}"\"
    bash: parameter: unbound variable
    

    Now with that out of the way, quick look into docs:

    ${#parameter}

    The length in characters of the expanded value of parameter is substituted.

    So with variable parameter not being set:

    $ echo ${#parameter}
    0
    

    or with set -u:

    $ echo ${#parameter}
    bash: parameter: unbound variable
    

    Additional # changed meaning to Remove matching prefix pattern. using: ${parameter#word} or ${parameter##word} syntax on ${#}, i.e. number of argument passed to a script/function. Good way to see and understand that behavior would be:

    $ f() { echo -n "$# " ; echo ${##parameter}; }
    $ f
    0 0
    $ f a b c
    3 3
    

    As you see in first call ${#} was 0 and (and attempting to strip prefix "parameter" does nothing to it really) and the second call value of ${#} is 3.

    Prefix removal, the different between # and ## is, when matching patterns whether shorted or longest match is stripped.