mm:ss calculator from shell prompt? - linux

From a shell prompt, what's the fewest-keystrokes way to calculate the mm:ss value of expressions such as
4:33 + 0:20 - 2:45 = 2:08 ?
This is for interactive use, not for use in a script, or measuring elapsed time, or anything fancy like that. No mouse. No GUI.
There are thousands of implementations of mm+60*ss and (mmss/60, mmss%60), in hundreds of languages. I could write a script in bash or ruby or C for this, to add yet another implementation. But it seems likely that this wheel doesn't need reinventing, when it's likely buried somewhere in bc, dc, irb, or maybe even in bash itself.

Although not perfect:
s="4:33 + 0:20 - 2:45"
n=$(sed 's/\([0-9]*\):\([0-9]*\)/(\1 * 60 + \2)/g' <<< "$s" | bc)
printf "%d:%02d\n" $(( $n / 60 )) $(( $n % 60 ))
The sed command outputs (4 * 60 + 33) + (0 * 60 + 20) - (2 * 60 + 45) to bc.
The output is: 2:08.

It is impossible in some few characters on prompt to calculate the time like this.
You can do for example something like:
date -d "4:33 + 2:22" +%H:%M
but you need to include time zone (and how time is being calculated), take the output, calculate again and! do not exceed 24hs. So this is ridiculous.
One of the possible solutions can be GNU/Units. It provides shorthand names for some common combinations:
hms -> hours, minutes, seconds
time -> years, days, hours, minutes and seconds
You have: 2 hours + 23 minutes + 32 seconds
You want: seconds
* 8612
/ 0.00011611705
Homepage: http://www.gnu.org/software/units/

Related

Do math on CSH or SH only with string variables

I have string variables MIN and SEC (minute and seconds).
MIN = "1"
SEC = "34"
I want to do calculations on these.
TOTSEC = MIN*60 + SEC
I tried:
expr $SEC + $MIN * 60
Result:
expr: non-numeric argument
Let it be known I am running busybox on a custom microcomputer and so have no access to bash,bc, and that other solution provides.
In sh, by which I'll assume you mean a POSIX shell, your best option is to use Arithmetic Expansion:
$ MIN=1
$ SEC=34
$ TOTSEC=$(( MIN * 60 + SEC ))
$ printf '%d\n' "$TOTSEC"
94
In csh however, the built-in math works quite differently:
% set MIN = 1
% set SEC = 34
% # TOTSEC = ( $MIN * 60 + $SEC )
% printf '%d\n' "$TOTSEC"
94
According to the man page, the # command permits numeric calculations to be performed and the result assigned to a variable.
Note that the expr command is external to the shell, so it should be usable from either one.
In sh:
$ TOTSEC=$(expr "$MIN" \* 60 + "$SEC")
And in csh:
% set TOTSEC = `expr "$MIN" \* 60 + "$SEC"`
Note: your sh may not be POSIX compliant. Most likely, it's ash, which is the ancestor of dash and FreeBSD's /bin/sh. You'll need to test in your environment.

Crontab setting - execute script every 55 minutes

I found a interesting thing during creation of my crontab setting.
I used this command:
crontab -e
and fill this line:
*/55 * * * * export DISPLAY=:0 && /home/user/Documents/script.sh $2>/dev/null
My idea was create scheduler, which start script.sh every 55 minutes.
But this script is execute in this times (for example):
08:55, 09:00, 09:05, 09:55, 10:00, 10:05, ...
and I don't know why.
Can someone explain me that?
Replace the script like this and it should work.
*/5 * * * * [ $(( $(date +%s) / 60 % 55 )) -eq 0 ] && export DISPLAY=:0 && /home/user/Documents/script.sh $2>/dev/null
minute-hour-day-month-year
* any value
, value list separator
- range of values
/ step values
Another option is a self-replicating 'at' job. Only advantage over cron is that it is less obvious, and also if you needed it to kick off not every X minutes, but X minutes after the last job completed. So your script will just contain a line to create a new 'at' job before it exits. Something like:
echo "/full/path/to/my/script > /root/myScript.at.log" | at now + X minutes
so every 5 minutes it will do this:
number of seconds elapsed since 1. 1. 1970 will divided by 60 = how many minutes
echo $(date +%s)
1476201056 ... second
echo $(( $(date +%s) / 60 ))
24603351 ... minutes
after that it will use modulo on count of minutes
When result of modulo is 0, it will send TRUE value.
And it is a typical logical AND
[ $((......)) -eq 0 ] && export DISPLAY.. && .../script.sh
Thank you.
It is really helpful :)

Setting cron for 5 minutes and 30 seconds

Hey I got crontab that runs every 5 minutes and it looks like this
*/5 * * * * blablalba
How can I get it running every 5 minutes and 30 seconds?
Instead of using Cron, have your script re-start itself using this as the final line:
echo /path/to/script | at now + 330 seconds
Or to be more "precise" in the timing : take into accoutn how many seconds you spend running the script and take those out of the 330 seconds (5mn and 30s) :
#beginning of script
seconds_at_start=$(date +%s)
....
#end of script
seconds_at_end=$(date +%s)
nb_seconds=$((330 + seconds_at_start - seconds_at_end))
echo /path/to/script | at now + $nb_seconds seconds
Note: you may want to use bc for the calculation part to avoid running into strange behaviour in case your version of shell can't handle arithmetics on numerical as high as those returned by date +%s ...
If your version of at doesn't allow "now + XX second", then you can :
compute the number of seconds the script ran for
compute how many seconds to sleep ( sleep N ) to reach the next minute
and then : echo /path/to/script | at now + X minute

How to set timezone in gnuplot?

I have a simple gnuplot command file:
....
set xdata time
set timefmt "%s"
set format x "%H:%M"
....
where x - timestamp column.
Result - time in UTC format. Can I change local timezome for x axis ?
Just came across this in the docs today:
The conversion to and from seconds assumes Universal Time (which is the same
as Greenwich Standard Time). There is no provision for changing the time
zone or for daylight savings. If all your data refer to the same time zone
(and are all either daylight or standard) you don't need to worry about these
things. But if the absolute time is crucial for your application, you'll
need to convert to UT yourself.
From help time/date
I just ran across this today. You don't need to change the format, just change the data. If data.txt contains timestamps in UTC, and you want to display them in PDT (-7 hours off from UTC), simply use:
plot 'data.txt' using ($1+(-7*3600)):2
This subtracts 7 hours (in seconds) from each x value.
A bit late to the party, and I don't have enough reputation points to comment, but to add to anthony and hermannk's answer, this is how I implemented it with their information:
in command.gnuplot, assuming that the first field contains the date/time and the second field contains the value for the Y axis:
plot "inputfile" using ($1 - offset):2
from the (bash) command line, when invoking gnuplot:
gnuplot -e "offset=$(date +%s -d '1 Jan 1970')" command.gnuplot
The offset generally will work OK because gnuplot internally interprets date/time as seconds from epoch. I don't know if the form "offset=$(date ...)" is a bash specific thing, but you could always use "offset=`date ...`" instead.
EDIT --
I found this not to work very well when dealing with DST/Summer Time changes. I changed the offset calc to this, and now it works better:
in command.gnuplot, assuming that the first field contains the date/time and the second field contains the value for the Y axis:
plot "inputfile" using ($1 + offset):2
from the (bash) command line, when invoking gnuplot:
gnuplot -e "offset=$(echo "$(date +%z) * 36" | bc)" command.gnuplot
How does this work?
date +%z provides the timezone offset in the form -0400 or similar, which means Local_Time = UTC - 4 hours. If we consider this a number (-400), then the offset, in seconds, is -400 / 100 * 3600 = -400 * 36.
Note that this won't work with timezones that have 30 minutes increments (India?), but I'm sure with some creating math, you can cover that as well.
In addition to previous correct answer, there is how I do this under bash
From version 4.1 of bash, you could avoid using forks to date for this:
printf -v tzoff "%(%z)T" -1
tzoff=${tzoff:0:1}$(( ( 10#${tzoff:1:2}* 3600 + 10#${tzoff:3:2}* 60 ) ))
Some samples:
TZ=Asia/Katmandu printf -v tzoff "%(%z)T" -1
echo $tzoff
+0545
tzoff=${tzoff:0:1}$(( ( 10#${tzoff:1:2}* 3600 + 10#${tzoff:3:2}* 60 ) ))
echo $tzoff
+20700
TZ=America/Chihuahua printf -v tzoff "%(%z)T" -1
echo $tzoff
-0700
tzoff=${tzoff:0:1}$(( ( 10#${tzoff:1:2}* 3600 + 10#${tzoff:3:2}* 60 ) ))
echo $tzoff
-25200
Then alternatively add this $tzoff to values while creating .dat file or by adding them in plot command file.
printf -v plotcmd 'plot \47file.dat\47 using ($1%s):2' $tzoff
echo "$plotcmd"
plot 'file.dat' using ($1-25200):2
The snippet posted here did not work for me, but this seems to do the trick:
TZ=Europe/Amsterdam tzoff=$(printf "%(%z)T")
tzoff=${tzoff:0:1}$(( ( 10#${tzoff:1:2} * 3600 + 10#${tzoff:3:2}* 60 ) ))
echo $tzoff

Cronjob every 25 hours?

How do I set up a cronjob that runs every 25th hour?
Just a guess, but you don't
Best hack off the top of my head: write a script to track the last time it was run, and conditionally run it if it was more than 25 hours ago.
Cron that driver script to run every hour.
It would be easier to issue an at command specifying the time and date of the next job when you start the current one but you could simulate that with a cronjob by updating the cronjob entry for the process at the start of the current run (not at the end 'cos then you'd have to take into account the time to run the job).
Setup a hourly job and check in your script if 25 hours are past with this snipnet:
if [ $((((`date +%s` - (`date +%s` % 3600))/3600) % 25)) -eq 0 ] ; then
your script
fi
You can achieve any frequency if you count the hours(, minutes, days, or weeks) since Epoch, add a condition to the top of your script, and set the script to run every hour on your crontab:
#!/bin/bash
hoursSinceEpoch=$(($(date +'%s / 60 / 60')))
# every 25 hours
if [[ $(($hoursSinceEpoch % 25)) -ne 0 ]]; then
exit 0
fi
date(1) returns current date, we format it as seconds since Epoch (%s) and then we do basic maths:
# .---------------------- bash command substitution
# |.--------------------- bash arithmetic expansion
# || .------------------- bash command substitution
# || | .---------------- date command
# || | | .------------ FORMAT argument
# || | | | .----- formula to calculate minutes/hours/days/etc is included into the format string passed to date command
# || | | | |
# ** * * * *
$(($(date +'%s / 60')))
# * * ---------------
# | | |
# | | ·----------- date should result in something like "1438390397 / 60"
# | ·-------------------- it gets evaluated as an expression. (the maths)
# ·---------------------- and we can store it
And you may use this approach with minutely, hourly, daily, or monthly cron jobs:
#!/bin/bash
# We can get the
minutes=$(($(date +'%s / 60')))
hours=$(($(date +'%s / 60 / 60')))
days=$(($(date +'%s / 60 / 60 / 24')))
weeks=$(($(date +'%s / 60 / 60 / 24 / 7')))
# or even
moons=$(($(date +'%s / 60 / 60 / 24 / 656')))
# passed since Epoch and define a frequency
# let's say, every 13 days
if [[ $(($days % 13)) -ne 0 ]]; then
exit 0
fi
# and your actual script starts here
You could use the 'sleep' or 'watch' commands to have a script run in a loop. Just make sure you script is executed.
I think you should try this
0 */25 * * * ...

Resources