21

I'm trying to add a function to my bash_profile for :

function git-unpushed {
    brinfo=$(git branch -v | grep git-branch-name)
    if [[ $brinfo =~ ("[ahead "([[:digit:]]*)]) ]]
    then
        echo "(${BASH_REMATCH[2]})"
    fi
}

But I get the following error:

bash: conditional binary operator expected`

bash: syntax error near =~'

From what I can find, the "equals tilde" operator (=~) evaluates as regex in bash.

Why is =~ is throwing an error?

UPDATE: Here's a screenshot of inputting it manually (this is running sh.exe):

Screenshot of equals tilde (=~) operator failing

Community
  • 1
  • 1
Aaron Blenkush
  • 2,937
  • 2
  • 24
  • 49

4 Answers4

26

I had the same error on Bash 3.1.0 from Git installation on Windows. Ultimately I changed it to:

if echo $var | grep -E 'regexp' > /dev/null
then
  ...
fi
Lukasz Korzybski
  • 6,521
  • 1
  • 25
  • 27
13

According to https://groups.google.com/forum/#!topic/msysgit/yPh85MPDyfE this is because msys doesn't ship libregex along with bash. Supposedly if you compile/find an msys built libregex, and put it in the library path, =~ starts working fine.

Eris
  • 6,648
  • 1
  • 23
  • 43
  • 1
    Great pointer. Unfortunately, simply replacing msysgit's `msys-regex-1.dll` with one from MSYS does _not_ work. What does _seem_ to work (try at your own risk), is to copy the following files from an MSYS installation's `bin` directory to msysgit's `bin` directory: `bash.exe`, `sh.exe`, `msys-termcap-0.dll` - in other words: replace bash altogether. However, at that point you may as well just use MSYS directly, using only `git.exe` from msysgit - see http://stackoverflow.com/q/5885393/45375 – mklement0 Mar 08 '15 at 16:42
7

Update 2015: msysgit is now obsolete.
You should use the bash which comes with git-for-windows.
As mentioned in this answer, it uses a much more recent bash (4.3+), for which the =~ syntax will work.


Original answer (march 2013)

The bash packaged with msysgit might simply be too old to fully support this operator.
It is certainly too old to compare with unquoted regex, as mentioned in "Bash, version 3" and "How do I use regular expressions in bash scripts?":

As of version 3.2 of Bash, expression to match no longer quoted.

Actually, mklement0 mentions in the comments:

=~ was introduced in bash 3.0 and always supported an unquoted token on the RHS.
Up to 3.1.x, quoted tokens were treated the same as unquoted tokens: both were interpreted as regexes.
What changed in 3.2 was that quoted tokens (or quoted substrings of a token) are now treated as literals.

But I tried with quotes (in the latest msysgit 1.8.1.2), and it still fails:

vonc@voncvb /
$ /bin/bash --version
GNU bash, version 3.1.0(1)-release (i686-pc-msys)
Copyright (C) 2005 Free Software Foundation, Inc.
vonc@voncvb /
$ variable="This is a fine mess."
vonc@voncvb /
$ echo "$variable"
This is a fine mess.
vonc@voncvb /
$ if [[ "$variable" =~ T.........fin*es* ]] ; then echo "ok" ; fi
bash: conditional binary operator expected
bash: syntax error near `=~'
vonc@voncvb /
$ if [[ "$variable" =~ "T.........fin*es*" ]] ; then echo "ok" ; fi
bash: conditional binary operator expected
bash: syntax error near `=~'
vonc@voncvb /
Community
  • 1
  • 1
VonC
  • 1,042,979
  • 435
  • 3,649
  • 4,283
  • 1
    Re "too old to compare with unquoted regex": `=~` was introduced in bash 3.0 and _always_ supported an _unquoted_ token on the RHS. Up to 3.1.x, _quoted_ tokens were _treated the same_ as unquoted tokens: both were interpreted as regexes. What changed in 3.2 was that _quoted_ tokens (or quoted substrings of a token) are now treated as _literals_. – mklement0 Mar 08 '15 at 13:49
  • @mklement0 good point. I have included your comment in the answer for more visibility. – VonC Mar 08 '15 at 13:55
1

Here is a solution that supports extracting matched strings. If the operator =~ is not supported by bash, then the sed command is used (installed with msysgit)

if eval "[[ a =~ a ]]" 2>/dev/null; then
    regexMatch() { # (string, regex)
        eval "[[ \$1 =~ \$2 ]]"
        return $?
    }
elif command -v /bin/sed >/dev/null 2>&1; then
    regexMatch() { # (string, regex)
        local string=$1
        if [[ ${2: -1} = $ ]]; then
            local regex="(${2%$})()()()()()()()()$"
        else
            local regex="($2)()()()()()()()().*"
        fi
        regex=${regex//\//\\/}
        local replacement="\1\n\2\n\3\n\4\n\5\n\6\n\7\n\8\n\9\n"
        local OLD_IFS=$IFS
        IFS=$'\n'
        BASH_REMATCH=($(echo "$string" | /bin/sed -rn "s/$regex/$replacement/p" | while read -r; do echo "${REPLY}"; done))
        IFS=$OLD_IFS
        [[ $BASH_REMATCH ]] && return 0 || return 1
    }
else
    error "your Bash shell does not support regular expressions"
fi

Usage example:

if regexMatch "username@host.domain" "(.+)@(.+)"; then
    echo ${BASH_REMATCH[0]}
    echo ${BASH_REMATCH[1]}
    echo ${BASH_REMATCH[2]}
fi
  • 2
    Note that nobody uses msygit anymore: it is now obsolete and replaced with git-for-windows (https://github.com/git-for-windows/git/releases), which has a much more recent bash 4.x (http://stackoverflow.com/a/26826359/6309) – VonC Oct 23 '15 at 11:08
  • Wow, I do not regret switching to Linux. – Aaron Blenkush Oct 24 '15 at 04:34
  • @Vonc after dealing with this insanity for a while (I think I first encountered it in August), I just took git-for-windows for a spin and am blown away at how much of the stupid annoyances that it fixes vs. msysgit (e.g. lack of any intellegent defaults for vim, lack of a resizable terminal, etc). I think I started using msysgit in 2011 or 2012 and didn't know there was anything better (perhaps there wasn't at the time?). Honestly I don't know why this suggestion is buried in a comment - perhaps you should consider making it an answer? IMHO it's the best answer here. – David Goldstein Nov 27 '15 at 08:16
  • @DavidGoldstein I didn't even noticed I put an answer 3 years ago in this very page! I have update my old answer to make clearer which git distribution for Windows to use. – VonC Nov 27 '15 at 08:26