Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

In bash, suppose that I have a string strname:

strname="ph7go04325r"

I would like to extract the characters between the first "3" character and the last "r" character in strname, saving the result in a string strresult. In the example above, the resulting strresult would be:

strresult="25"

The first "3" character is not necessarily at string position 8 in strname; likewise, the last "r" is not necessarily at string position 11. Thus, both of the following strings strname should yield strresult="25":

strname="ph11go04325raa"
strname="325r"
strname="rgo04325raa"

Also, strname=ph12go04330raa" should yield strresult="30".

I am new to bash scripting, and I don't know where to begin to do string pattern matching like this. Do you have any suggestions?

share|improve this question

2 Answers 2

up vote 6 down vote accepted

You can use a regex in bash (3.0 or above) to accomplish this:

if [[ $strname =~ 3(.+)r ]]; then
    strresult=${BASH_REMATCH[1]}
else
    echo "unable to parse string $strname"
fi

In bash, capture groups from a regex are placed in the special array BASH_REMATCH. Element 0 contains the entire match, and 1 contains the the match for the first capture group.

share|improve this answer

In standard sh syntax (so would work with any version of bash or any other POSIX compliant shell), you would do:

case $strname in
  (*3*r*) 
    strresult=${strname#*3}
    strresult=${strresult%r*};;
  (*)
    printf >&2 '%s\n' "Unable to parse string $strname"
esac

See also the old expr solution which will even work on 35 year old Unices:

expr "x$strname" : 'x[^3]*3\(.*\)r'

The old quirk with expr is that if the match fails you get a non-zero exit status (fine), but you also get a non-zero exit status if the returned strings resolves to 0 (like with strname=zz300rzz).

share|improve this answer
    
I think your phrasing incorrectly implies that this can only be done with older versions of bash. The parameter expansion is, of course, still a fine approach in modern shells. –  kojiro Feb 4 '13 at 20:55
    
@kojiro, I see what you mean. The initial formulation was to follow-up on Jordan's answer. I've updated my answer. –  Stéphane Chazelas Feb 4 '13 at 21:02

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.