How can I find time difference between two server timestamps? - bash

This outputs the closest Google server's time:
// Closest Google Server:
date +"%s" -d "$(curl -s --head http://google.com | grep ^Date: | sed 's/Date: //g')"
// Result: 1234
This outputs my local server time:
// Server
date +"%s"
// Result: 1235
How can I fetch the seconds between each result? (in the example above: 1)

Strictly answering your question, how about:
echo $(( $(date +"%s") - $(date +"%s" -d "`curl -s --head http://google.com | grep ^Date: | sed 's/Date: //g'`") ))

Related

Shell operator "||" did not work as expected?

I am trying to get the file time from the HTTP Header with the following command.
curl -sLI http://sgp-ping.vultr.com/vultr.com.100MB.bin | grep -i '^Last-Modified' | cut -c16- | date -f- '+%F %T'
Under normal circumstances, it can return query results.
If the query fails due to network problems, it will return null.
I want to return the current system time when the query fails. So I use the shell operator "||", which is used as follows.
curl -sLI http://sgp-ping.vultr.com/xxx.bin | grep -i '^Last-Modified' | cut -c16- | date -f- '+%F %T' || date '+%F %T'
But it doesn't work as expected, what's wrong with it?
Any help, thanks in advance!
If you are writing a script you can deal with it via $? just need to allow for it.
e.g.
#!/bin/bash
doTheCurl() {
curl -v -sLI -o /dev/null "$1" 2>&1 | grep -i '< Last-Modified:'
[ $? -ne 0 ] && date '+%F %T'
}
doTheCurl "http://sgp-ping.vultr.com/vultr.com.100MB.bin"
doTheCurl "http://non-sgp-ping.vultra.com/xxx.bin"
Gives this [I ignored extracting / formatting - but you can see the results are different because they came from different paths.].
< Last-Modified: Wed, 28 Oct 2020 18:06:00 GMT
2021-03-12 16:24:19
The first one fails because the grep doesn't match anything - so it then gives the date.
You can do whatever you like - pipe thru sed or whatever after.

Pipe CURL result to BC

I have a CURL command
echo "{cur_format}" | curl -w #- -s -o /dev/null https://example.com
Let's say the above command outputs a string of "I waited 1 day".
How can I convert "I waited 1 day" to "I waited 24 hours" (i.e. pipe "1 * 24" to the bc command")?
Thank you.
I managed to resolve this by using "awk" command. For example,
echo "{cur_format}" | curl -w #- -s -o /dev/null https://example.com | awk -F'[:\|]' '{print $1 ":" (($2*24)) "|" $3 "|" $4;}'
Note that -F'[:\|]' is a list of any delimiters you need.

Determine how many days a certificate is still valid from within bash script

I want to check how many days the certificate of a website is valid from within a bash script which runs on a standard Ubuntu 14.04 server. openssl is available.
I already figured out that I can use openssl to get the target date
$ echo | openssl s_client -connect google.com:443 2>/dev/null|openssl x509 -noout -enddate
notAfter=Dec 22 16:37:00 2016 GMT
But how do I parse the resulting date and subtract the current one? Or might there be a better solution?
Just in single line
echo "(" $(date -d "`openssl x509 -in /etc/letsencrypt/live/d-herrmann.de/cert.pem -text -noout | grep "Not After" | cut -c 25-`" +%s) - $(date -d "now" +%s) ")" / 86400 | bc
With GNU date's %j to get day of the year and arithmetic expansion for subtraction:
$ echo $(( $(date -d "$(cut -d= -f2 <(echo 'notAfter=Dec 22 16:37:00 2016 GMT'))" '+%j') - $(date '+%j')))
73
$(date -d "$(cut -d= -f2 <(echo 'notAfter=Dec 22 16:37:00 2016 GMT'))" '+%j') gets us the day of the year from the date we have got, replace teh echo command inside process substitution, <(echo 'notAfter=Dec 22 16:37:00 2016 GMT') with the openssl command you have used initially
$(date '+%j') gets us today's date as day of the year
$(()) is used for subtracting the integers
date1="Dec 22 16:37:00 2016 GMT" # Future date
date2=$(date) # Current date
diff=$(($(date -d "$date1" +%j)-$(date -d "$date2" +%j))) #Diff between two date, %j is to show day of the year.
echo $diff #Display difference
73
Or just in one line:
echo $(($(date -d "Dec 22 16:37:00 2016 GMT" +%j)-$(date +%j)))
73
Here is a little script, which returns days, hours or minutes a cert is still valid, I just saved it in an executable file e.g. check_cert_age.sh
#!/bin/bash
# input domain as first parameter eg. ./heck_cert_age.sh stackoverflow.com
input="$1"
domain=$(echo "$input" | sed -e 's|^[^/]*//||' -e 's|/.*$||')
#domain=stackoverflow.com
echo
echo "Check the cert of Domain $domain"
datetime=$(timeout 5 openssl s_client -servername $domain -connect $domain:443 2>/dev/null | openssl x509 -noout -dates | sed 's/notAfter=\(.*\)$/\1/' | tail -n1)
if [ -z "$datetime" ]; then
echo
echo "ERROR"
echo
exit 0
fi
localtime=$(date -d "${datetime}" '+%R')
localdate=$(date -d "${datetime}" '+%Y-%m-%d')
timestamp=$(date -d "${datetime}" '+%s')
now=$(date '+%s')
diff=$((($timestamp-$now)/60))
if [ "$diff" -gt 3599 ] || [ "$diff" -lt 3599 ]; then
diffstr="$(expr $diff / 60 / 24) days"
elif [ "$diff" -gt 59 ] || [ "$diff" -lt 59 ] ; then
diffstr="$(expr $diff / 60) h"
else
diffstr="$diff min"
fi
echo
echo "The cert is valid until $localdate at $localtime ($diffstr)"
echo
The output will be:
Check the cert of Domain stackoverflow.com
The cert is valid until 2023-02-01 at 15:10 (50 days)
The output make a difference in days, hours, minutes and knows the difference to the local timezone. For minutes, it would look e.g. like that:
Check the cert of Domain ssl-cert-almost-expired.com
The cert is valid until 2022-12-13 at 15:39 (34 min)

How can I subtract timestamp results from `date` in one line of shell?

I can generate two timestamps like so:
date +"%s" -d "$(curl -s --head http://google.com | grep ^Date: | sed 's/Date: //g')"
// Result: 1417800327
date +"%s"
// Result: 1417800325
How can I subtract them with only one line?
echo "$((1417800327-1417800325))"
// Result: 2
But I want something closer to:
echo "$(( (date +"%s" -d "$(curl -s --head http://google.com | grep ^Date: | sed 's/Date: //g')") - (date +"%s")))"
Try doing this :
LANG=C echo $(( $(date +%s) - $(date -d "$(curl -s --head http://google.com 2>&1 | awk -F'Date: ' '/^Date:/{print $2}')" +%s) ))
or splitted multi-lines for readability :
LANG=C echo $((
$(date +%s) - $(
date -d "$(curl -s --head http://google.com |
awk -F'Date: ' '/^Date:/{print $2}'
)" +%s)
))
#!/bin/bash
##On Linux. start time, do something, find end time.
st=`date +%s`; sleep 10; et=`date +%s`;
##On SunOS instead of using date command, use `truss /usr/bin/date 2>&1 | grep ^time | awk -F"= " '{print $2}'`;
##substract to find elapsed time
elt=$((et-st));
##find elapsed hours, minutes, seconds
eh=$((elt/3600)); em=$(($((elt%3600))/60)); es=$(($((elt%3600))%60));
elt=`printf "%02d:%02d:%02d%s" $((eh)) $((em)) $((es))`;
##show elapsed time in user friendly way
echo - Elapsed time: $elt
Output:
- Elapsed time: 00:00:10
Using a subshell function with one big command bash line
(timestamp=`date +"%s" -d "$(curl -s --head http://google.com | grep ^Date: | sed 's/Date: //g')"`;date=`date +"%s"`;let "time_difference= $timestamp-$date";echo "$time_difference"; )

Shell script comparing dates

I'm working on a shell script that scrapes a date off a webpage and then checks if it is in the last three days of the current date (running it in Cygwin). If the test passes, it simply echoes "PASS", and if it fails, it echoes "FAIL";
However, when I run my script, I get the following:
integer expression expected: 1317618000
FAIL
Here is the script:
updateStr=$(curl "http://www.mywebsite.com" | grep "Last Update")
dateStr=(`echo $updateStr | sed -e 's/.*Last Update: \([^<]*\)<.*/\1/'`)
update=$(date -d "$dateStr" +%s)
epoch=$(date -d "-3 days ago" +%s)
test "$update" -ge "$epoch" && echo "PASS" || echo "FAIL"
Any ideas on what the issue is?
Edit
Here is the result of running bash -x on the script:
$ bash -x check_date.sh
++ curl http://www.mywebsite.com
++ grep 'Last Update'
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 6542 100 6542 0 0 789 0 0:00:08 0:00:08 --:--:-- 1544
+ updateStr=' <span style="float:right">Last Update: 10/3/2011 2:
'8:45 AM</span></p>
++ echo '<span' 'style="float:right">Last' Update: 10/3/2011 2:58:45 'AM</span><
'p>
++ sed -e 's/.*Last Update: \([^<]*\)<.*/\1/'
' dateStr='(10/3/2011 2:58:45 AM)
' +%ste -d '(10/3/2011 2:58:45 AM)
+ update=$'1317618000\r'
++ date -d '-3 days ago' +%s
+ epoch=$'1317938194\r'
+ test $'1317618000\r' -ge $'1317938194\r'
: integer expression expected1317618000
+ echo FAIL
FAIL
Update
I tried removing the carriage returns that appear in the date outputs, but it's still not working. Here is the updated script:
updateStr=$(curl "http://mywebsite.com" | grep "Last Update")
dateStr=$(echo $updateStr | sed -e 's/.*Last Update: \([^<]*\)<.*/\1/')
update=$(date -d "$dateStr" +%s | tr -d '\r')
epoch=$(date -d "3 days ago" +%s | tr -d '\r')
echo "Last Update: $update"
echo "Epoch Date: $epoch"
test "$update" -ge "$epoch" && echo "PASS" || echo "FAIL"
And here is the result:
$ bash -x ./check_date.sh
++ curl http://mywebsite.com
++ grep 'Last Update'
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 6542 100 6542 0 0 17398 0 --:--:-- --:--:-- --:--:-- 19704
+ updateStr=' <span style="float:right">Last Update: 10/6/2011 2:
'0:02 AM</span></p>
++ echo '<span' 'style="float:right">Last' Update: 10/6/2011 2:40:02 'AM</span><
'p>
++ sed -e 's/.*Last Update: \([^<]*\)<.*/\1/'
' dateStr='10/6/2011 2:40:02 AM
' +%ste -d '10/6/2011 2:40:02 AM
++ tr -d '\r'
+ update=$'1317886802\r'
++ date -d '-3 days ago' +%s
++ tr -d '\r'
+ epoch=$'1318184767\r'
' echo 'Last Update: 1317886802
Last Update: 1317886802
' echo 'Epoch Date: 1318184767
Epoch Date: 1318184767
+ test $'1317886802\r' -ge $'1318184767\r'
: integer expression expected: 1317886802
+ echo FAIL
FAIL
The carriage returns might be in your script itself. Try running dos2unix on your script.
Try this:
update=$(date -d "$dateStr" +%s | tr -d '\r')
epoch=$(date -d "-3 days ago" +%s | tr -d '\r')
That will get rid of the carriage returns at the end of each number, which might help.
bash is determining from context (the presence of '\r' in this case) that these are strings and not integers. The '-ge' binary operator expects integer arguments and so it's throwing an error. Tom Zych's suggestion will work, as well as using string comparison operators, like '<' or '>', which might give unexpected results if the string is badly formatted for some reason. I'm not sure if there is a way to force date to output as an integer or not...
References:
http://tldp.org/LDP/abs/html/untyped.html
http://tldp.org/LDP/abs/html/comparison-ops.html

Resources