Remove pattern from beginning of string using only Bash pattern matching

Viewed 130

Is it possible to remove a pattern from only the beginning of a string using Bash's built-in pattern matching and parameter substitution? (Bash 5.0.18)

Given the following array:

myparams=( --some-param -h --15 -q 100 )

I would like to loop through the elements and output the following (strip all -s from the front without affecting any that might come after). Desired output:

some-param
h
15
q
100

I am aware of Bash Hackers Wiki - Substring removal but I didn't see any way to do this.

Here is one failed attempt, Almost works, but some- gets clobbered:

$ for p in "${myparams[@]}"; do echo "$p ==> ${p##*-}" ; done
--some-param ==> param
-h ==> h
--15 ==> 15
-q ==> q
100 ==> 100

Another failed attempt, this time some-param becomes someparam:

$ for p in "${myparams[@]}"; do echo "$p ==> ${p//-}" ; done
--some-param ==> someparam
-h ==> h
--15 ==> 15
-q ==> q
100 ==> 100

Here's a working solution, but it relies on sed (tested with sed from macOS 10.15.7):

$ for p in "${myparams[@]}"; do echo "$p ==> $(sed 's/^-*//'<<<"$p")" ; done
--some-param ==> some-param
-h ==> h
--15 ==> 15
-q ==> q
100 ==> 100

And finally, here's a working method that uses BASH_REMATCH — is this the only builtin way?:

$ for p in "${myparams[@]}"; do [[ $p =~ ^(-*)?(.*) ]]; echo "$p ==> ${BASH_REMATCH[2]}" ; done
--some-param ==> some-param
-h ==> h
--15 ==> 15
-q ==> q
100 ==> 100
1 Answers

Use an extended pattern and parameter expansion:

shopt -s extglob
printf '%s\n' "${myparams[@]##+(-)}"
  • +(-) matches one or more dashes
  • # removes the string only at the beginning of the value
  • ## matches the longest string possible
  • Using an array as the parameter removes the prefixes from all its members
Related