3

I have a function vercomp that compares two version strings and determines which one is greater. When I add this alias:

alias grep='grep -EI --colour=always'

to a seemingly unrelated part of my bashrc file I get this error:

-bash: 10#24 > 10#24: syntax error: invalid arithmetic operator (error token is "24 > 10#24")
-bash: 10#24 < 10#24: syntax error: invalid arithmetic operator (error token is "24 < 10#24")

Note that the error is emitted twice, I'm assuming because the error is processed twice (i.e. this isn't a typo on my part). Note that when I remove the alias, everything works fine. Why is this error being generated and how do I mitigate it?

The lines that are of interest, below, are probably the ones marked:

    if ((10#${ver1[i]} > 10#${ver2[i]})); then
        return 1
    fi
    if ((10#${ver1[i]} < 10#${ver2[i]})); then
        return 2
    fi

EDIT: Adding more context

I'm using GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin11) on Mac OS X 10.7.5 (Lion). I'm calling vercomp like this:

if [[ $OS = 'Mac' ]]; then                                                                                                                                                                                 
    ### EMACS VERSION CHECK                                                                                                                                                                                
    # make sure that we're working with emacs >= 24                                                                                                                                                        
    wanted_ver=24                                                                                                                                                                                          
    curr_ver=`emacs --version | grep -oE '[[:digit:]]+\.[.[:digit:]]*'`                                                                                                                                    
    echo $curr_ver                                                                                                                                                                                         
    vercomp $curr_ver $wanted_ver

Note that I'm calling grep to initialize curr_ver. I still can't figure out why the error is happening though, but using grep -EI --colour doesn't generate the error, so that answers the second part of my question. Does anyone know why the error happens?


vercomp () {
    ## returns: 0 equal
    ##          1 ver1 > ver 2
    ##          2 ver1 < ver 2
    if [[ $1 == $2 ]]; then
        return 0
    fi

    # IFS (Internal Field Separator) Fields are separated by a '.'
    # ($var) notation means turn $var into an array according to the IFS.
    local IFS=.
    local i ver1=($1) ver2=($2)

    # fill empty fields in ver1 with zeros
    # ${#var[@]} = the number of elements in the array/var.
    for ((i=${#ver1[@]}; i<${#ver2[@]}; i++)); do
        ver1[i]=0
    done
    for ((i=0; i<${#ver1[@]}; i++)); do
        if [[ -z ${ver2[i]} ]]; then
            # fill empty fields in ver2 with zeros
            ver2[i]=0
        fi
        # <num>#$var converts the value of $var to the base of <num>
        if ((10#${ver1[i]} > 10#${ver2[i]})); then
            return 1
        fi
        if ((10#${ver1[i]} < 10#${ver2[i]})); then
            return 2
        fi
    done
    return 0
}
Son of the Wai-Pan
  • 12,371
  • 16
  • 46
  • 55
  • using the solution from the mighty dennis williams http://stackoverflow.com/a/4025065/297323 – Fredrik Pihl Apr 24 '14 at 07:34
  • Which bash are you using? If I insert your code preceded by the alias (with bash 4.2 under Debian), vercomp works fine in all three test cases (less, equal, greater). Also show us how you're calling it. – paxdiablo Apr 24 '14 at 07:36
  • @paxdiablo your comment helped me find a solution so that it doesn't error out. Thanks! But I still don't know why it happens. – Son of the Wai-Pan Apr 24 '14 at 07:50
  • @Avery, now that you've added the fact you're creating one of the variables, it's evident that the `--color=ALL` is causing it to be surrounded with escape sequences. See the update to my answer for details on how to check (and fix). – paxdiablo Apr 24 '14 at 08:15
  • Credit disclaimer: `vercomp()` comes from [this answer here](http://stackoverflow.com/a/4025065/612462). – Adrian Frühwirth Apr 24 '14 at 08:21

2 Answers2

4

Using the aliased grep to produce either of the two variables that you're passing to vercomp, you'll almost certainly find that you have escape sequences in the output produced.

That's because you have explicitly told grep to do so with --color=ALL, as per the grep man page:

--color[=WHEN]: Surround the matched (non-empty) strings, matching lines, context lines, file names, line numbers, byte offsets, and separators (for fields and groups of context lines) with escape sequences to display them in color on the terminal.

This should become evident if you place code like:

echo "$1" | od -xcb
echo "$2" | od -xcb

at the start of your vercomp function. The escape sequences should be easily detectable in that case.

In fact, if I execute the following code in a script that has your vercomp function in it:

curr_ver=$(echo 21.7 | grep -EI --color=always '^..')
echo "$curr_ver" | od -xcb
vercomp $curr_ver 21.5

the output is:

0000000    5b1b    3130    333b    6d31    5b1b    324b    1b31    6d5b
        033   [   0   1   ;   3   1   m 033   [   K   2   1 033   [   m
        033 133 060 061 073 063 061 155 033 133 113 062 061 033 133 155
0000020    5b1b    2e4b    0a37
        033   [   K   .   7  \n
        033 133 113 056 067 012
0000026
./qq.bash: line 30: 10#21 > 10#21: syntax error: invalid arithmetic
    operator (error token is "21 > 10#21")
./qq.bash: line 33: 10#21 < 10#21: syntax error: invalid arithmetic
    operator (error token is "21 < 10#21")

So you can see both that:

  • there are escape sequences in the output to colorise your found terms; and
  • it generates similar errors to what you see.

If you get rid of the colorisation (even if only temporarily), you should find the errors disappear.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
2

This is why you should not alias grep to grep --colour=always and it does exactly what you ask it to do borking stdout in your pipe with ANSI escape codes. This is what grep --colour=auto is for which only kicks in when outputting to a terminal.

You can either

  1. change your alias to use --colour=auto:

    alias grep='grep -EI --colour=auto'

    or

  2. bypass the alias by using \grep:

    curr_ver=$(emacs --version | \grep -oE '[[:digit:]]+\.[.[:digit:]]*')

The reason why --colour works is because without argument it defaults to --colour=auto (http://git.savannah.gnu.org/cgit/grep.git/tree/src/grep.c):

case COLOR_OPTION:
        if (optarg)
          {
            if (!strcasecmp (optarg, "always") || !strcasecmp (optarg, "yes")
                || !strcasecmp (optarg, "force"))
              color_option = 1;
            else if (!strcasecmp (optarg, "never") || !strcasecmp (optarg, "no")
                     || !strcasecmp (optarg, "none"))
              color_option = 0;
            else if (!strcasecmp (optarg, "auto") || !strcasecmp (optarg, "tty")
                     || !strcasecmp (optarg, "if-tty"))
              color_option = 2;
            else
              show_help = 1;
          }
        else
          color_option = 2;    # <--- HERE: default to 2 (auto)
        break;
Adrian Frühwirth
  • 42,970
  • 10
  • 60
  • 71