Home > Back-end >  regex works in perl, fails to match in bash, works in zsh but BASH_REMATCH is empty
regex works in perl, fails to match in bash, works in zsh but BASH_REMATCH is empty

Time:12-03

for d in "A - test1 (a)" "B - test2 (b)";
do
  if [[ "$d" =~ -\s(.*?)\s\( ]];
  then
    D="${BASH_REMATCH[1]}"
    echo "$d --> $D : $BASH_REMATCH"
  else
    echo "NO MATCH $d"
  fi
done

In bash this outputs

NO MATCH A - test1 (a)
NO MATCH B - test2 (b)

In zsh, it fails

zsh: failed to compile regex: Unmatched ( or \(

If I modify the expression to [[ "$d" =~ "-\s(.*?)\s\(" ]] in zsh it matches but with no capture

A - test1 (a) -->  : 
B - test2 (b) -->  :

A Perl script with the same regex expression does work

$x="A - test1 (a)";

if ($x =~ /-\s(.*?)\s\(/) {
   print "$x -> $1\n";
} else {
   print "No match: $x\n";
}

This outputs A - test1 (a) -> test1 as expected.

How can I make the regex work (extracting test from A - test1 (a) as per this example) in both bash and zsh?

CodePudding user response:

With bash use [[:space:]] instead of \s and remove the ?:

for d in "A - test1 (a)" "B - test2 (b)"; do
  if [[ "$d" =~ -[[:space:]]([^[:space:]]*)[[:space:]]\( ]]; then
    D="${BASH_REMATCH[1]}"
    echo "$d --> $D"
  else
    echo "NO MATCH $d"
  fi
done
A - test1 (a) --> test1
B - test2 (b) --> test2

With zsh it is almost the same, except that you must use match instead of BASH_REMATCH and quote the final parenthesis of your regexp:

for d in "A - test1 (a)" "B - test2 (b)"; do
  if [[ "$d" =~ -[[:space:]]([^[:space:]]*)[[:space:]]'\(' ]]; then
    D="${match[1]}"
    echo "$d --> $D"
  else
    echo "NO MATCH $d"
  fi
done
A - test1 (a) --> test1
B - test2 (b) --> test2
  • Related