I have a string in Bash which may or may not start with any number of leading spaces, e.g.
" foo bar baz"
" foo bar baz"
"foo bar baz"
I want to delete the first instance of "foo" from the string, and any leading spaces (there may not be any).
Following the advice from this question, I have tried the following:
str=" foo bar baz"
regex="[[:space:]]*foo"
echo "${str#$regex}"
echo "${str#[[:space:]]*foo}"
If str has one or more leading spaces, then it will return the result I want, which is _bar baz
(underscore = leading space). If the string has no leading spaces, it won't do anything and will return foo bar baz
. Both 'echoes' return the same results here.
My understanding is that using *
after [[:space:]]
should match zero or more instances of [[:space:]], not one or more. What am I missing or doing wrong here?
EDITS
@Raman - I've tried the following, and they also don't work:
echo "${str#[[:space:]]?foo}"
echo "${str#?([[:space:]])foo}"
echo "${str#*([[:space:]])foo}"
All three solutions will not delete 'foo' whether or not there is a trailing space. The only solution that kind of works is the one I posted with the asterisk - it will delete 'foo' when there is a trailing space, but not when there isn't.
The best thing to do is to use parameter expansions (with extended globs) as follows:
# Make sure extglob is enabled
shopt -s extglob
str=" foo bar baz"
echo "${str##*([[:space:]])}"
This uses the extended glob *([[:space:]])
, and the ##
parameter expansion (greedy match).
Edit. Since your pattern has the suffix foo
, you don't need to use greedy match:
echo "${str#*([[:space:]])foo}"
is enough.
Note. you can put foo
in a variable too, but just be careful, you'll have to quote it:
pattern=foo
echo "${str#*([[:space:]])"$pattern"}"
will work. You have to quote it in case the expansion of pattern
contains glob characters. For example when pattern="foo[1]"
.