How can I compare the hour to a string/number in bash? - bash

We have a server which we use to run Selenium tests with our extension (for Chrome and Firefox). We run the Selenium tests every 2 hours. I want to run different tests after 14:00 than before 14:00. I have this variable:
start_hour=`TZ='Asia/Tel_Aviv' date +"%H"`
And I know how to compare it to a specific hour, such as 08:00 AM (it's a string):
if [ "$start_hour" = "08" ]; then
...
fi
But how do I check if this variable shows an hour after 14:00 (including 14:00), or before 14:00? Can I compare strings in bash and how? I just want to check if $start_hour is >= "14", or not?
Is the answer different if I want to check after 08:00 AM or before?

To perform greater or less-than comparisons, the test operations -gt, -le, -ge, and -le exist.
start_hour=$(TZ='Asia/Tel_Aviv' date '+%k')
[ "$start_hour" -ge 8 ]
Note the use of %k vs %H, and 8 vs 08 -- a leading 0 can prevent your numbers from being interpreted as decimal.
Similarly, in native bash syntax, for a numeric comparison:
start_hour=$(TZ='Asia/Tel_Aviv' date '+%k')
(( start_hour >= 8 ))
If your shell is bash, and not /bin/sh, and you truly do want an ASCII-sort string comparison, you can use > and < inside of [[ ]]:
start_hour=$(TZ='Asia/Tel_Aviv' date '+%H')
[[ $start_hour > 08 || $start_hour = 08 ]]

Related

How to find a bug in my date arithmetic shell script?

I wrote below piece of code to calculate the date after a given date:
date=$DATE_FINAL
declare -a max_month=(0 31 28 31 30 31 30 31 31 30 31 30 31)
eval $(echo $date|sed 's!\(....\)\(..\)\(..\)!year=\1;month=\2;day=\3!')
(( year4=year%4 ))
(( year100=year%100 ))
(( year400=year%400 ))
if [ \( $year4 -eq 0 -a \
$year100 -ne 0 \) -o \
$year400 -eq 0 ]
then
declare -a max_month=(0 31 28 31 30 31 30 31 31 30 31 30 31)
fi
day=$((day+1))
if [ $day -gt ${max_month[$month]} ] >| /wload/baot/home/baoted9/logs_bde27_conversion_1/ataa_display.logs 2>&1
then
day=1
month=$((month+1))
if [ $month -gt 12 ]
then
year=$((year+1))
month=1
fi
fi
if [ $month -eq "08" ] || [ $month -eq "09" ]
then
future_date_final=$(echo $year"$month"$day)
else
future_date_final=$(printf "%4.4d%2.2d%2.2d" $year $month $day)
fi
echo "this is your final business date $future_date_final"
It calculates the date correctly however throws an error at the end of the code as below -
line 79: 08: value too great for base (error token is "08")
It just looks too ugly, not sure how to remove it as otherwise code is working fine, tried redirecting it to a log file still appearing.
Also, I am facing issue with below code for a plain cd command with code highlighted in red -
echo "pset date $Param_date_1"
cd /wload/baot/home/baotasa0/sandboxes_finance/ext_ukba_bde/pset >| /wload/baot/home/baoted9/logs_bde27_conversion_1/at_display.logs 2>&1
sh UKBA_publish.sh UKBA $Param_date_1 3 >| /wload/baot/home/baoted9/logs_bde27_conversion_1/ate_display.logs 2>&1
Error is -
./auto2.sh: line 190: syntax error: unexpected end of file
The problem is, that if you're using $((val+1)) where $val is beginning with a 0, then bash isn't operating on decimal base but on octal base. Since 08 isn't a valid number in octal base, it complains.
You can force decimal representation by writing
$((10#$val+1))
Please note, that by doing so, any preceding zeros are removed. If you need to have a representation with preceding zero, just use
val=$(printf '%02d' $((10#$val+1)))
For reference, see the bash manual:
Constants with a leading 0 are interpreted as octal numbers. A leading ‘0x’ or ‘0X’ denotes hexadecimal. Otherwise, numbers take the form [base#]n, where the optional base is a decimal number between 2 and 64 representing the arithmetic base, and n is a number in that base. If base# is omitted, then base 10 is used. When specifying n, the digits greater than 9 are represented by the lowercase letters, the uppercase letters, ‘#’, and ‘_’, in that order. If base is less than or equal to 36, lowercase and uppercase letters may be used interchangeably to represent numbers between 10 and 35.
P.S.: This is a very good article about falsehoods programmers believe about time I had to read myself. If possible, try to use date -d instead of doing manual date arithmetic. You can use for instance date -d "+5 days" +%d.%m.%Y to get the date in five days.

date comparison not working properly in shell script

I want to compare dates in shell script.
The logic I am using as below :
$date_1="Tue Nov 25 23:50:01 CST 2014"
$date_2=$(date)
if [ $date_2 -eq $date_1 ] ; then
echo "$date2 is equal to $date_1"
else
echo "$date2 is not equal to $date_1"
fi
However when I am executing the script using crontab for every minute,
I got the below message in log which is not correct :
Tue Nov 25 23:50:01 CST 2014 is not equal to Tue Nov 25 23:50:01 CST 2014
Could you please help me out of this embarrassing situation?
Assuming this job is running every minute. You can do:
date_1="Tue Nov 25 23:50:01 CST 2014"
dt1=$(date -d "$date_1" '+%Y%m%d%H%M')
dt2=$(date '+%Y%m%d%H%M')
if [ "$dt1" -eq "$dt2" ]; then
echo "$dt2 is equal to $date_1"
else
echo "$dt2 is not equal to $date_1"
fi
Best thing would be to format your date strings to look like numbers, starting with year, then month, etc. You probably would want to code a greater than or equal, or less than or equal, in case cron skips a second now or then:
date_1=$(date +%Y%m%d%H%M%S)
sleep 10
date_2=$(date +%Y%m%d%H%M%S)
if [ $date_2 -ge $date_1 ] ; then
echo "$date_2 is greater than or equal to $date_1"
else
echo "$date_2 is less than $date_1"
fi
Output:
20141126063044 is greater than or equal to 20141126063034
Beware you don't want the $ in front of the variable when you are setting it!

How to decode Seagate's hard drive date code in a Bash script

Seagate hard drives display a code instead of the manufacturing date. The code is described here and an online decoder is available here.
In short, it's a 4 or 5 digit number of the form YYWWD or YYWD, where:
YY is the year, 00 is year 1999
W or WW is the week number beginning 1
D is day of week beginning 1
Week 1 begins on the first saturday of July in the stated year
Examples
06212 means Sunday 20 November 2005
0051 means Saturday 31 July 1999
How can this be decoded in a bash script ?
This is what I did, it should work:
#!/bin/bash
DATE=$1
REGEX="^(..)(..?)(.)$"
[[ $DATE =~ $REGEX ]]
YEAR=$(( ${BASH_REMATCH[1]} + 1999 ))
WEEK=$(( ${BASH_REMATCH[2]} - 1))
DAYOFWEEK=$(( ${BASH_REMATCH[3]} - 1))
OFFSET=$(( 6 - $(date -d "$YEAR-07-01" +%u) ))
DATEOFFIRSTSATURDAY=$(date -d "$YEAR-7-01 $OFFSET days" +%d)
FINALDATE=`date -d "$YEAR-07-$DATEOFFIRSTSATURDAY $WEEK weeks $DAYOFWEEK days"`
echo $FINALDATE
It worked for the two dates given above...
If you want to customize the date output, add a format string at the end of the FINALDATe assignment.
Here is a short script, it takes two arguments: $1 is the code to convert and $2 is an optional format (see man date), otherwise defaulted (see code).
It uses the last Saturday in June instead of the first one in July because I found it easer to locate and it allowed me to just add the relevant number of weeks and days to it.
#!/bin/bash
date_format=${2:-%A %B %-d %Y}
code=$1
[[ ${#code} =~ ^[4-5]$ ]] || { echo "bad code"; exit 1; }
let year=1999+${code:0:2}
[[ ${#code} == 4 ]] && week=${code:2:1} || week=${code:2:2}
day=${code: -1}
june_last_saturday=$(cal 06 ${year} | awk '{ $6 && X=$6 } END { print X }')
date -d "${year}-06-${june_last_saturday} + ${week} weeks + $((${day}-1)) days" "+${date_format}"
Examples:
$ seadate 06212
Sunday November 20 2005
$ seadate 0051
Saturday July 31 1999
I created a Seagate Date Code Calculator that actually works with pretty good accuracy. I've posted it here on this forum for anyone to use: https://www.data-medics.com/forum/seagate-date-code-conversion-translation-tool-t1035.html#p3261
It's far more accurate than the other ones online which often point to the entirely wrong year. I know it's not a bash script, but will still get the job done for anyone else who's searching how to do this.
Enjoy!

Changing variable on set of conditions

This question is related to the thread here:
Today's date, minus X days in shell script
But because I'm now manipulating the variable, I started another thread.
As described above, I need to get today's date minus 200 days, with the Year, Month, and Day in separate variables (in this question I'll use 200, though in the other it's 222). However, I need to represent January as 0, February as 1 (or 01), March as 2 (or 02), etc... I tried this:
MONTHS200=$(date -j -v-200d -v-1m +"%m")
if ${MONTHS200}=01; then
${MONTH200}=0
else ${MONTHS200}=${MONTH200}
fi
But I get the error ./update_newdateformat.sh: line 20: 12=01: command not found ./update_newdateformat.sh: line 23: 12=: command not found The -v-1m works for all months except January, because it goes to 12, instead of 0
Here's how to shift all the month number down by 1 n your script:
MONTHS200=$(date -j -v-320d +"%m")
# Remove leading zero if there is one, so it doesn't cause problems later
MONTHS200=${MONTHS200#0}
MONTHS200=$((MONTHS200-1))
Here is how to use if and = (assignment) syntax in shell:
if [[ "${MONTHS200}" == "01" ]]; then
MONTHS200="0"
else
MONTHS200=${AnotherVariable}
fi
Note that for numerical comparisons, you need to use:
-eq instead of ==
-ne instead of !=
-lt instead of <
-le instead of <=
-gt instead of >
-ge instead of >=
For example:
if [[ "${MONTHS200}" -eq 1 ]]; then
I would take advantage of bash features (I assume OSX bash is recent enough -- I might be wrong). You only need to call date once with
read year month day < <(date -j -v-200d +"%Y %m %d")
month=$(( 10#$month - 1 ))
You avoid the octal issue by forcing bash to use base-10

generate 5 minutes interval

I need to write a shell script that will create a list of 5 minutes interval times.
00-00
00-05
00-10
00-15
...
...
23-50
23-55
Here are the commands I have started with.
# date
Fri Sep 21 18:14:35 IST 2012
# date '+%H-%M'
18-14
# date '+%H-%M' --date='5 minute ago'
18-18
How do I write a script to generate the list?
If it is too complicated, I will do it manually since it is one time task.
Update:
The following script is working. But it will generate single digits like 7-5 should actually be 07-05
#!/bin/sh
for hour in `seq 0 24`
do
for minute in `seq 0 5 59`
do
echo $hour-$minute
done
done
A simple bash solution (version 4 or later):
printf "%s\n" {00..23}-{00..55..5}
If you need to start at a given date, you can use:
ITERATIONS=100 # adjust here
D=$(date +%s)
for ((i=0; i<$ITERATIONS; i++))
do
date '+%H-%M' -d #$((D+5*60*i))
done
The following shell scripting is returning the required data
#!/bin/sh
for hour in `seq -w 0 24`
do
for minute in `seq -w 0 5 59`
do
echo $hour-$minute
done
done

Resources