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
}
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:
If you get rid of the colorisation (even if only temporarily), you should find the errors disappear.
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
change your alias to use --colour=auto:
alias grep='grep -EI --colour=auto'
or
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;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With