How to replace a pattern in a string in bash How to replace a pattern in a string in bash shell shell

How to replace a pattern in a string in bash


You can use this sed:

sed -r 's/,(#.*)?[0-9]+//' filea1="aaa,bbb3,ccc,"a2="aaa,bbb,ccc,"a3="aaa,bbb,ccc,"


For your first question, you can use extglob for this.

$ a1="aaa,bbb3,12,ccc,"$ a2="aaa,2,bbb,ccc,"$ shopt -s extglob$ echo "${a1//,+([0-9]),/,}"aaa,bbb3,ccc,$ echo "${a2//,+([0-9]),/,}"aaa,bbb,ccc,$

It's well documented in Greg's wiki and many other places.


For your second question, you can handle this either with more advanced pattern matching, or by treating the comma-separated elements as fields and processing them individually.

First, a pattern match solution.

$ a1="aaa,bbb3,#zu_45,ccc,"$ a2="aaa,#mn,bbb,ccc,"$ a3="aaa,bbb,ccc,#kn,"$ echo "${a1//,#+([^,]),/,}"aaa,bbb3,ccc,$ echo "${a2//,#+([^,]),/,}"aaa,bbb,ccc,$ echo "${a3//,#+([^,]),/,}"aaa,bbb,ccc,$

(I'll just point out for any wandering readers that while patterns like this may look like regular expressions, they are not.)

Second, a solution that treats fields like fields would of course involve a loop. Here's an example as a one-liner:

$ a=(${a1//,/ }); unset newa; for i in "${a[@]}"; do if [[ ! $i =~ ^# ]]; then newa="$newa${newa:+,}$i"; fi; done; echo "$newa"aaa,bbb3,ccc

You can repeat this for the other variables.

Note that this depends on your data not having any spaces in it, since that's the character used to separate fields in a bash array.


Using pure bash, you can do:

$ re='(.*),[0-9]+,(.*)'$ a1="aaa,bbb3,12,ccc,"$ a2="aaa,2,bbb,ccc,"$ [[ $a1 =~ $re ]] && echo ${BASH_REMATCH[1]},${BASH_REMATCH[2]}aaa,bbb3,ccc,$ [[ $a2 =~ $re ]] && echo ${BASH_REMATCH[1]},${BASH_REMATCH[2]}aaa,bbb,ccc,

Those echos could be turned into assignments, giving you what you wanted.

Rather than doing a search and replace, you can just capture the parts before and after using ( ) and they will be stored in the special array variable $BASH_REMATCH.

For the second one, you could do something similar:

$ re='(.*),#[^,]*,(.*)'$ a1="aaa,bbb3,#zu_45,ccc,"$ a2="aaa,#mn,bbb,ccc,"$ a3="aaa,bbb,ccc,#kn,"$ [[ $a1 =~ $re ]] && echo ${BASH_REMATCH[1]},${BASH_REMATCH[2]}aaa,bbb3,ccc,$ [[ $a2 =~ $re ]] && echo ${BASH_REMATCH[1]},${BASH_REMATCH[2]}aaa,bbb,ccc,$ [[ $a3 =~ $re ]] && echo ${BASH_REMATCH[1]},${BASH_REMATCH[2]}aaa,bbb,ccc,

Using a [^,] (not a comma) character class ensures that the rest of the string isn't consumed.

update

You could turn this into a function like this:

$ rm_hash () { >     local re='(.*),#[^,]*,(.*)'>     local subject="$1">     [[ $subject =~ $re ]] && echo ${BASH_REMATCH[1]},${BASH_REMATCH[2]}> }$ a1="aaa,bbb3,#zu_45,ccc,"$ rm_hash $a1aaa,bbb3,ccc,