Bash: one parameter substitution: beginning and end of string

bashvariable substitution

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):

.foo_bar.kate-swp

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:

foo=".foo_bar.kate-swp"
foo="${foo#.}"
foo="${foo%.*}"
echo "$foo"
foo_bar

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/}"
.foo_bar

But

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

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

Best Answer

Some workarounds in Bash:

Regex match with capture:

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

Split the string to parts on the dots:

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

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#.}%%.*}'
foo_bar
Related Question