This question is not about how to accomplish this with sed, grep or similar tools. Please don't answer with those.

I have a string (it can be any string along the same structure foofoo_barbar, etc):


and I just one to retrieve foo_bar, so remove the . at the beginning and .kate-swp at the end. I know I can use intermediate varibles like this:

echo "$foo"

But I'm wondering if it can be done in just one substitution. I'm trying (and I mean a lot) along these lines:

echo "${foo/!(*[a-z]).kate-swp/}"


# just an example of my failures
echo "${foo/.!(*[a-z]).kate-swp/}"

Maybe this is not at all possible, but if it is, I'm always keen to learn.


1 Answer 1


Some workarounds in Bash:

Regex match with capture:

$ foo='.foo_bar.kate-swp'
$ [[ $foo =~ ^[.]([^.]+) ]] && echo ${BASH_REMATCH[1]}

Split the string to parts on the dots:

$ foo='.foo_bar.kate-swp'
$ IFS=. read -r x var y <<< "$foo"; echo "$var"

But really, no, you can't nest expansions in Bash in the useful way. And the ${var/pattern/replace} doesn't really work because the pattern needs to match a continuous part of the string, and there are no regex-style capture groups (i.e. no s/xxx(main)yyy/\1/).

You could nest the expansions in Zsh, though:

zsh% foo='.foo_bar.kate-swp'
zsh% echo ${${foo#.}%%.*}'
  • Thanks, I edited the question clarifying that the string coud be variable though with the same structure: echo "${foo:1:7}" would just work for that specific string. Mar 3, 2021 at 20:14
  • @schrodigerscatcuriosity, I know, that one is a joke ;) (I had it marked as such, but seem to have dropped it in an edit.) The others aren't really as brief as the nested expansion either.
    – ilkkachu
    Mar 3, 2021 at 20:14
  • Joke all around, I miss that in this site :) good humour is always refreshing. Mar 3, 2021 at 20:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.