How to read date from terminal and compare with current date - linux

I want to know the appropriate way of reading date from terminal and comparing with current date using shell script,
I have the below script,
a=`date +%Y-%m-%d`
while [ 1 ] ; do
echo "Enter Date"
read todate
if [ $todate < $a ];then
break;
fi
echo "todate greater than curDate"
done
it is not running as expected. Please help me.
UPDATE
Here is my final version,
#! /bin/bash
DATE=$(date '+%s')
while [ 1 ] ; do
echo "Enter Date[DD MM YYYY]:"
read D M Y
THIS=$(date -d "$Y-$M-$D" '+%s')
if (( THIS < DATE )) ; then
break
fi
done
Thanks everyone!

from Advanced Bash-Scripting Guide:
7.3. Other Comparison Operators
...
string comparison
...
<
is less than, in ASCII alphabetical order
if [[ "$a" < "$b" ]]
if [ "$a" \< "$b" ]
Note that the "<" needs to be escaped within a [ ] construct.
So, your
if [ $todate < $a ];then
becomes
if [ $todate \< $a ];then
or
if [[ $todate < $a ]];then

date has +%s format.
%s seconds since 1970-01-01 00:00:00 UTC
you save current date in second. Then convert user input date also in second. so you could compare.

Here is the solution:
Here in this solution i am converting dates to single integer and it is obvious that greater date will always be larger integer than current date
a=date +%Y%m%d
while [ 1 ] ; do
echo "Enter Date"
read todate
echo "$todate" > temp
for i in 1 2 3
do
y=`cut -d- -f$i temp`
x=$x$y
done
if [ $x -lt $a ];then
exit;
fi
echo "todate greater than curDate"
done

Related

Check date whether AM or PM in shell script and take action accordingly

I want to check whether its AM or PM in a shell script. I have tried this:
if ( `date "+%p"` -eq "AM" ); then echo "Yes"; else "NO"; fi
But it shows:
AM: command not found
Also tried = instead of -eq.
Two issues in your current statement:
1) the format specifier %p in GNU date utility may contain lowercase of either AM or PM - depending on your current locale. It's better to use %P specifier as it contains lowercase presentation
2) In bash, -eq - is integer comparison operator, not for string comparison
The right way would be:
if [ `date +%P` = "am" ]; then echo 'Yes'; else echo 'No'; fi
To deal with any locale you may compare the current hour value (given by %H) with midday hour 12:
if [ `date +%H` -lt 12 ]; then echo 'Yes'; else echo 'No'; fi
The locale can specify language- and/or country- specific strings to use in place of am and pm. For example:
$ LC_TIME=hu_HU date +%P
de
$ LC_TIME=fr_FR date +%P
$ LC_TIME=en_EN date +%P
pm
Instead, check the hour to see which half of the day would be used to provide a value for %P:
h=$(date +%H)
if (( h < 12 )); then
echo YES # am
else
echo NO # pm
fi
Or, force a known locale:
ampm=$(LC_TIME=C date +%P)
if [[ $ampm = am ]]; then
...
else
...
fi
here
# String comparision with =
# [ ] instead if ()
if [ `date "+%p"` = "AM" ]; then
echo "Yes";
else
echo "NO"; # Missed echo here
fi

How do I read all dates between start date and end date in linux

I want to read all dates between two range of dates and this ranges includes both start date and end date
input_start_date="2013-09-05"
input_end_date="2013-09-10"
START_DATE=$(date -I -d "$input_start_date") || exit -1
END_DATE=$(date -I -d "$input_end_date") || exit -1
d="$START_DATE"
while [ "$d" <= "$END_DATE" ]; do
echo $d
d=$(date -I -d "$d + 1 day")
done
but when I ran the above code I get below error
bash: = 2013-09-10: No such file or directory
Could someone help me to fix this issue
Expected output
2013-09-05
2013-09-06
2013-09-07
2013-09-08
2013-09-09
2013-09-10
start=2013-09-05
end=2013-09-10
while [[ $start < $end ]]
do
printf "$start\n"; start=$(date -d "$start + 1 day" +"%Y-%m-%d")
done
or you can try this one
END=$(date -d "2013-09-10" +%s);
DATE=$(date -d "2013-09-05" +%s);
while [[ "$DATE" -le "$END" ]]; do date -d "#$DATE" +%F; let DATE+=86400; done
The idea is right, but you just got the operator wrong, <= does not work with date strings in bash, you needed a inequality operator != in the condition.
while [ "$d" != "$enddate" ]; do
The <= operator works when used in arithmetic context in bash with the ((..)) operator.
Something little in awk (changed the range a bit since there was no test data, just the expected output):
$ awk '$0>="2013-09-06" && $0<="2013-09-09"' file
2013-09-06
2013-09-07
2013-09-08
2013-09-09
You kind of need a do-while loop here, which bash does not provide. How about
date="$start_date"
while true; do
echo "$date"
[[ $date = "$end_date" ]] && break
date=$(date -d "$date + 1 day" "+%F")
done
Don't use ALL_CAPS_VAR_NAMES -- too easy to mistakenly overwrite shell/system vars.

Read string and convert to INT (BASH)

I have a simple script in Bash to read a number in a file and then compare it with a different threshold. The output is this:
: integer expression expected
: integer expression expected
OK: 3
My code is this:
#!/bin/bash
wget=$(wget http://10.228.28.8/ -O /tmp/wget.txt 2>/dev/null)
output=$(cat /tmp/wget.txt | awk 'NR==6')
#output=7
echo $output
if [ $output -ge 11 ];then
echo "CRITICAL: $output"
exit 2
elif [ $output -ge 6 ] && [ $output -lt 11 ];then
echo "WARNING: $output"
exit 1
else
echo "OK: $output"
exit 0
fi
rm /tmp/wget.txt
I know what is the problem, I know that I'm reading a string and I try to compare a int. But I don't know how can I do to read this file and convert the number to read in a int var..
Any ideas?
The problem occurs when $output is the empty string; whether or not you quote the expansion (and you should), you'll get the integer expression required error. You need to handle the empty string explictly, with a default value of zero (or whatever default makes sense).
wget=$(wget http://10.228.28.8/ -O /tmp/wget.txt 2>/dev/null)
output=$(awk 'NR==6' < /tmp/get.txt)
output=${output:-0}
if [ "$output" -ge 11 ];then
echo "CRITICAL: $output"
exit 2
elif [ "$output" -ge 6 ];then
echo "WARNING: $output"
exit 1
else
echo "OK: $output"
exit 0
fi
(If you reach the elif, you already know the value of $output is less than 11; there's no need to check again.)
The problem also occurs, and is consistent with the error message, if output ends with a carriage return. You can remove that with
output=${output%$'\r'}
There are a couple of suggestions from my side regarding your code.
You could explicitly tell bash the output is an integer
declare -i output # See [1]
Change
output=$(cat /tmp/wget.txt | awk 'NR==6') # See [2]
may be better written as
output=$(awk 'NR==6' /tmp/wget.txt )
Change
if [ $output -ge 11 ]
to
if [ "0$output" -ge 11 ] # See [4]
or
if (( output >= 11 )) # Better See [3]
References
Check bash [ declare ].
Useless use of cat. Check [ this ]
Quoting [ this ] answer :
((...)) enable you to omit the dollar signs on integer and array variables and include spaces around operators for readability. Also empty variable automatically defaults to 0 in such a statement.
The zero in the beginning of "0$output" help you deal with empty $output
Interesting
Useless use of cat is a phrase that has been resounding in SO for long. Check [ this ]
[ #chepner ] has dealt with the empty output fiasco using [ bash parameter expansion ] in his [ answer ], worth having a look at.
A simplified script:
#!/bin/bash
wget=$(wget http://10.228.28.8/ -O /tmp/wget.txt 2>/dev/null)
output=$(awk 'NR==6' </tmp/wget.txt )
output="$(( 10#${output//[^0-9]} + 0 ))"
(( output >= 11 )) && { echo "CRITICAL: $output"; exit 2; }
(( output >= 6 )) && { echo "WARNING: $output"; exit 1; }
echo "OK: $output"
The key line to cleanup any input is:
output="$(( 10#${output//[^0-9]} + 0 ))"
${output//[^0-9]} Will leave only digits from 0 to 9 (will remove all non-numeric chars).
10#${output//[^0-9]} Will convert output to a base 10 number.
That will correctly convert numbers like 0019
"$(( 10#${output//[^0-9]} + 0 ))" Will produce a zero for a missing value.
Then the resulting number stored in output will be compared to limits and the corresponding output will be printed.
In BASH, It is a good idea to use double brackets for strings:
if [[ testing strings ]]; then
<whatever>
else
<whatever>
fi
Or double parenthesis for integers:
if (( testing ints )); then
<whatever>
else
<whatever>
fi
For example try this:
var1="foo bar"
if [ $var1 == 'foo bar' ]; then
echo "ok"
fi
Result:
$ bash: [: too many arguments
Now, this:
var2="foo bar"
if [[ $a == "foo bar" ]]; then
echo "ok"
fi
Result:
ok
For that, your code in BASH:
if [[ $output -ge 11 ]]; then
echo "CRITICAL: $output"
exit 2
elif [[ $output -ge 6 ]]; then
echo "WARNING: $output"
exit 1
else
echo "OK: $output"
exit 0
fi

If date string is + or - 5 minutes then

I am new to bash scripts and trying to work an if statement out.
I want to do a check to see if the date stamp of a file is + or - 5 minutes from the time now. I have so far:
#!/bin/bash
MODDATE=$(stat -c '%y' test.txt)
echo moddate= $MODDATE
MODDATE=$(echo $MODDATE |head --bytes=+16)
echo now = $MODDATE
currentdate2=$(date -d "+5 minutes" '+%Y-%m-%d %H:%M')
currentdate3=$(date -d "-5 minutes" '+%Y-%m-%d %H:%M')
echo currentdate2 = $currentdate2
echo currentdate3 = $currentdate3
So this gives me the datestamp of the file (MODDATE) and the date now + or - 5 minutes.
How can i do an IF statement to say "if $MODDATE is between $currentdate2 (+5 minutes from now) and $currentdate3 (-5 minutes from now)" then echo [1] > output.txt ELSE echo [0] > output.txt .
Thank you for all of your help in advance
I recommend you to use date %s to have the date in seconds since 1/1/1970 and make date comparison much easier.
currentdate2=$(date -d "+5 minutes" '+%s')
currentdate3=$(date -d "-5 minutes" '+%s')
Hence,
if [ $moddate -ge $currentdate2 ] && [ $moddate -le $currentdate3 ]; then
....
fi
should make it.
Or even shorter:
[ $moddate -ge $currentdate2 ] && [ $moddate -le $currentdate3 ] && echo "in interval!"
How about you don't try to parse the output of stat and directly take its output in seconds since Epoch with %Y? It would then be easier to use Bash's arithmetic.
Your script would look like this (with proper quoting, modern Bash constructs and lowercase variable names):
#!/bin/bash
moddate=$(stat -c '%Y' test.txt)
echo "moddate=$moddate"
now=$(date +%s)
if ((moddate<=now+5*60)) && ((moddate>=now-5*60)); then
echo "[1]" > output.txt
else
echo "[0]" > output.txt
fi

Is value in range with bash shell

In bash shell, how can be value checked if within range by most effective way?
Example:
now=`date +%H%M`
if [ $now -ge 2245 ] && [ $now -le 2345 ] ; then
...
fi
...this one is working, but with using now variable.
Other option is:
if [ $((`date +%H%M`)) -ge 2245 ] && [ $((`date +%H%M`)) -le 2345 ] ; then
...
fi
...without variable, but with execution of date twice.
How to do it with one date execution and no variable at all?
First off, as a general rule, I'm pretty sure you need EITHER to use a variable OR run the command twice to do multiple comparisons on arbitrary numbers. There is no such notation as if [ 1000 -lt $(date '+%H%M') -lt 2000 ];.
Also, you don't need to put your backquoted commands inside $((...)). The result of the backquoted command is a string which /bin/[ will be interpreted by -gt or -le as a number.
if [ `date '+%H%M'` -gt 2245 -a `date '+%H%M'` -lt 2345 ]; then
That said, as an option for the times in your example, you can try using a smarter date command line.
In FreeBSD:
if [ `date -v-45M '+%H'` -eq 22 ]; then
Or in Linux:
if [ `date -d '45 minutes ago' '+%H'` -eq 22 ]; then
You can use Shell Arithmetic to make your code clear.
now=`date +%H%M`
if ((2245<now && now<2345)); then
....
fi
I would write:
if ( now=$(date +%H%M) ; ! [[ $now < 2245 ]] && ! [[ $now > 2345 ]] ) ; then
...
fi
which is mostly equivalent to your first example, but restricts the $now variable to a subshell (...), so at least it doesn't pollute your variable-space or risk overwriting an existing variable.
It also (thanks to shellter's comment) avoids the problem of $now being interpreted as an octal number when %H%M is (for example) 0900. (It avoids this problem by using string comparison instead of integer comparison. Another way to avoid this problem would be to prefix all values with a literal 1, adding 10,000 to each of them.)
#!/bin/bash
while :
do
MAX_TIME="1845"
MIN_TIME="1545"
if ( now=$(date +%H%M) ; ! [[ $now < $MIN_TIME ]] && ! [[ $now > $MAX_TIME ]] ) ;
then
echo "You are in time range and executing the commands ...!"
else
echo "Maximum Time is $MAX_TIME ...!"
# echo "Current Time is $now .....!"
echo "Minimum Time is $MIN_TIME ....!"
fi
sleep 4
done
#nohup sh /root/Date_Comp.sh > /dev/null 2>&1 &

Resources