Search code examples
bashshellksh

Bash/ksh substring removal


As per documentation:

${string#substring}   # strip shortest match
${string##substring}  # strip longest match

However, while testing I get:

$ string="abcABC123ABCabc"
$ echo ${string#a*C}
123ABCabc
$ echo ${string##a*C}
abc

so far worked as expected, however...

$ echo ${string#B*c}
abcABC123ABCabc
$ echo ${string##B*c}
abcABC123ABCabc

I would expect that the 3rd echo have returned abcABC123A (stripping away the shortest match) and the 4th would return abcA

What is wrong there?


Solution

  • ${var#prefix} and ${var##prefix} are anchored to the beginning of the string.

    ${var%suffix} and ${var%%suffix} are anchored to the end of a string.

    If you want an unanchored replacement, then you should use ${var/pattern/subst} (which can have subst left empty, as in, ${string/a*C/}, or ${var//pattern/subst} (which works the same way, but replaces all instances of pattern, not only the first).


    If your goal is an unanchored, non-greedy substring removal, you could do it with an extglob, but personally, I'd use a regex written to emulate non-greediness using character classes:

    re='^(.*)(b[^C]*C)(.*)'
    
    [[ $string =~ $re ]] && result="${BASH_REMATCH[1]}${BASH_REMATCH[3]}"`
    

    ...whereas the extglob approach would look like:

    shopt -s extglob
    result=${string/b*([^C])C/}