5

I'm running a pretty simple bash script in ubuntu but have come up with a problem. If needed I'll post the whole script, but I've narrowed down the problem. Basically, I want to run some code every 15 seconds, so I started with this:

time=`date +%S`

time2=$((time%15))

if [ $time2 -eq 0 ]

then

etc, etc, etc....

The problem comes up when time is 08 seconds. The script terminates with Illegal number: 08. Adding to that, when using:

time2=$(($time%15))

instead of the illegal number error, it would terminate with Arithmetic expression: expecting EOF: "08%15"

I'm guessing 08 isn't interpreted as a number. Or there's some base issue, like it thinks it's in octal or something. Any help?

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
  • 3
    08 is likely interpreted as octal in most C-style languages and systems. – OregonGhost May 18 '09 at 15:16
  • 1
    @OregonGhost: Indeed. And, more specifically, 08 isn't a valid number in octal, hence the error message. By comparison, that's equivalent to counting in hex and going from 0x0F to 0x0G, i.e. you can't do that ;-) – Mike Spross May 18 '09 at 15:37

6 Answers6

6

Shortest solution:

time2=$(( ${time#0} % 15 ))

${var#glob} means "$var with glob removed from the beginning if present".

ephemient
  • 198,619
  • 38
  • 280
  • 391
4

Try using the following flags instead

date +%-S

It says given the -, it won't pad. It has problems with the base, interpreting it as an octal integer.

Anyway, if you want to do something every 15 seconds, i find this one easier to follow:

while ((1)); do 
    echo do something now...
    sleep 15s
done
Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
4

Force Bash to interpret the number in decimal, no matter how many padded zeros:

time2=$((10#$time % 15))
TheBonsai
  • 15,513
  • 4
  • 22
  • 14
2

you're right, it was interpreting it as octal. bourne shells do that for any number with a leading 0 in an Arithmetic Substition:

#~ $ echo $(( 010 ))
8
#~ $ echo $(( 0100 ))
64
#~ $ echo $(( 10#0100 ))
100
#~ $ echo $(( 40#lolwut ))
2213236429 

look in the manpage for 'base#' to see all the details about this '#-forcing' thing. you can get pretty ridiculous with it if you want to

jrrs
  • 98
  • 4
  • that is what I was looking for thx, btw, any way to revert back from this with '40#': 34581 ? :) – Aquarius Power Jul 23 '14 at 04:00
  • 1
    i think this does what you want: https://github.com/jrrs/sh/blob/master/lib/math/tobasen jrrs@iorek:~$ ksh -c '. github/sh/lib/math/tobasen ; tobasen -b 40 34581' lol – jrrs Aug 06 '14 at 00:22
1

Since you're only interested in "every fifteen seconds" rather than running things on the minute exactly you could use date +%s (lowercase s) which will give you the number of seconds since the start of the epoch. This won't have a leading 0 so your script should run fine.

However, I would wonder about your code in a wider context. If the system is running very slow for some reason it could be possible for the script only be run second 14 and then second 16 meaning it will miss an execution.

It might be worth touching a file when you do whatever it is the script does and then performing your action when then last modified date of the file is 15 or more seconds ago.

David Webb
  • 190,537
  • 57
  • 313
  • 299
  • I know what you mean, some seconds are jumped/ignored. The purpose of this script however was just to test with seconds, because I'll be using this for every 15 minutes. But I'll probably have to check your answer, because I might not want this script constantly running. –  May 18 '09 at 15:28
1

That does look like it's interpreting it as octal.

Try date +%S | sed -e 's/^0//'

pjc50
  • 1,856
  • 16
  • 18