48

In a text file, test.txt, I have the next information:

sl-gs5 desconnected Wed Oct 10 08:00:01 EDT 2012 1001

I want to extract the hour of the event by the next command line:

hour=$(grep -n sl-gs5 test.txt | tail -1 | cut -d' ' -f6 | awk -F ":" '{print $1}')

and I got "08". When I try to add 1,

 14 echo $((hour+1))

I receive the next error message:

./test2.sh: line 14: 08: value too great for base (error token is "08")

If variables in Bash are untyped, why?

avivamg
  • 12,197
  • 3
  • 67
  • 61
RobertoFRey
  • 674
  • 1
  • 5
  • 10
  • 2
    The leading 0 is leading to bash trying to interpret your number as an octal number, but octal numbers are 0-7, and 8 is thus an invalid token. – Charles D Pantoga Jan 21 '17 at 20:00
  • This error comes from "leading zero" error AKA any 0 digit that comes before the first non-zero representation in bash. examples ( for example 01 ,002 , 0000003 etc... ) – avivamg Sep 19 '19 at 14:44

8 Answers8

118

See ARITHMETIC EVALUATION in man bash:

Constants with a leading 0 are interpreted as octal numbers.

You can remove the leading zero by parameter expansion:

hour=${hour#0}

or force base-10 interpretation:

$((10#$hour + 1))
choroba
  • 231,213
  • 25
  • 204
  • 289
  • 23
    You can also force the base-10 interpretation: `$((10#$hour+1))`. – chepner Oct 10 '12 at 16:03
  • This is not working for my bash and negative numbers: `lat=-048 ; latd=${lat#0} ; echo $latd ; echo $((latd-1))` gives me `-048` and then the same error. – Luis A. Florit Feb 12 '16 at 00:14
  • 1
    @LuisA.Florit: Of course, as `#0` removes zero from the start of the string, and there's a `-` instead. Use `shopt -s extglob ; latd=${latd#?(-)0}`. – choroba Feb 12 '16 at 00:17
  • What's funny is that the $((10#$hour + 1)) does not work either for negative numbers. Thanks! – Luis A. Florit Feb 12 '16 at 00:22
  • 1
    The problem with that is that you get the absolute value (in the example, `47` instead of `-49`. It seems this needs a longer oneliner maybe with `sed`,`bc` or something that I wanted to avoid since mine is inside a big loop. I hate this octal thing `bash` do. It should be possible to configure it with a `shopt`. – Luis A. Florit Feb 12 '16 at 00:28
  • 1
    Numbers with an optional leading `+` or `-` can be handled with `$((${hour%%[^-+]*}10#${hour#[-+]}))` – Grisha Levit Jun 29 '21 at 05:55
17

what I'd call a hack, but given that you're only processing hour values, you can do

 hour=08
 echo $(( ${hour#0} +1 ))
 9
 hour=10 
 echo $(( ${hour#0} +1))
 11

with little risk.

IHTH.

shellter
  • 36,525
  • 7
  • 83
  • 90
10

You could also use bc

hour=8
result=$(echo "$hour + 1" | bc)
echo $result
9
makim
  • 3,154
  • 4
  • 30
  • 49
  • 1
    It worked for me so +1 however, I was looking for some simple soln like result=int("$hour + 1") – Somum Aug 24 '15 at 11:22
3

Here's an easy way, albeit not the prettiest way to get an int value for a string.

hour=`expr $hour + 0`

Example

bash-3.2$ hour="08"
bash-3.2$ hour=`expr $hour + 0`
bash-3.2$ echo $hour
8
jbrahy
  • 4,228
  • 1
  • 42
  • 54
3

In Short: In order to deal with "Leading Zero" numbers (any 0 digit that comes before the first non-zero) in bash - Use bc An arbitrary precision calculator language

Example:

a="000001"
b=$(echo $a | bc)
echo $b

Output: 1

From Bash manual:

"bc is a language that supports arbitrary precision numbers with interactive execution of statements. There are some similarities in the syntax to the C programming lan- guage. A standard math library is available by command line option. If requested, the math library is defined before processing any files. bc starts by processing code from all the files listed on the command line in the order listed. After all files have been processed, bc reads from the standard input. All code is executed as it is read. (If a file contains a command to halt the processor, bc will never read from the standard input.)"

avivamg
  • 12,197
  • 3
  • 67
  • 61
2

Since hours are always positive, and always 2 digits, you can set a 1 in front of it and subtract 100:

echo $((1$hour+1-100))

which is equivalent to

echo $((1$hour-99))

Be sure to comment such gymnastics. :)

user unknown
  • 35,537
  • 11
  • 75
  • 121
1

The leading 0 is leading to bash trying to interpret your number as an octal number, but octal numbers are 0-7, and 8 is thus an invalid token.

If I were you, I would add some logic to remove a leading 0, add one, and re-add the leading 0 if the result is < 10.

Charles D Pantoga
  • 4,307
  • 1
  • 15
  • 14
1

How about sed?

hour=`echo $hour|sed -e "s/^0*//g"`
Feng Xue
  • 71
  • 4