Reputation: 707
I would like to use bash parameter expansion on an array to include items matching a given pattern, rather than to exclude them.
Here's an example excluding the items matching ba*
:
ar=( foo bar baz qux )
for i in ${ar[@]##ba*}; do
echo "$i"
done
# foo
# qux
That's all well and good, but in this case I'd actually like to include only the items matching ba*
.
Here's what I've tried, and frankly, I'm not quite sure how to interpret the results:
ar=( foo bar baz qux )
#shopt -s extglob # seems to have no effect either way
for i in ${ar[@]##!(ba*)}; do
echo "$i"
done
# ar
# az
It looks like I'm in this case I'm getting the right items, but their values have been munged.
Here's my current working solution:
ar=( foo bar baz qux )
for i in ${ar[@]}; do
if [[ "$i" =~ ba* ]]; then
echo "$i"
fi
done
# bar
# baz
I am using Mac OSX and have tested this with Mac bundled bash 3.2.51 as well as Homebrew installed bash 4.2.45.
Thanks!
Edit
@casc (rightly) suggests below to just re-append the removed 'b' from the matches, but that's not exactly what I'm looking for.
My actual use case would be more like including items that match *ba*
, not just ba*
. The point is that I don't necessarily know the full string, just that it will definitely have the pattern ba*
somewhere. This may be a better example:
ar=( foo zoobar waybaz qux )
for i in ${ar[@]}; do
if [[ "$i" =~ ba* ]]; then
# do something with $i
fi
done
# zoobar
# waybaz
Upvotes: 1
Views: 285
Reputation: 11
Why not simply prepend the chopped-off b
again?
(
shopt -s extglob
ar=( foo bar baz qux )
for i in ${ar[@]/#!(ba*)}; do
echo "b${i}"
done
)
# ... or ...
(
export IFS=""
ar=( foo bar baz qux )
ar=( ${ar[@]/#!(ba*)} )
ar=( ${ar[@]/#/b} )
echo ${!ar[*]}
printf '%s\n' "${ar[@]}"
)
Further alternatives include:
ar=( foo bar baz qux )
printf '%s\n' "${ar[@]}" "${ar[@]##ba*}" | sort | uniq -u
printf '%s\n' "${ar[@]}" "${ar[@]/#ba*}" | sort | uniq -u
# alternative to current working solution
(
array=( foo bar baz qux )
for item in "${ar[@]}"; do
case "$item" in
ba*) echo "$item";;
*) :;;
esac
done
)
Upvotes: 1
Reputation: 531490
From each element of the array, you are removing the longest prefix that does not match ba*
.
foo
and qua
, the entire string does not match.bar
and baz
, b
does not match ba*
, but ba
does, so only b
is removed.Upvotes: 1