I'm checking the age of an object, and it gives me one of the following types of outputs, e.g: 30s, 15m, 3h, 17d. (meaning 30 seconds, 15 minutes, 3 hours, 17 days, respectfully)
Each of these is just a simple string.
What's the best way to say: "if under 15m, continue, else break"?
I can only think of
if 's' or 'm' not in 'string' then break
if 'm' in 'string' and '2-digits-preceding-m' > 15 then break
Is there a more elegant way of doing this, possibly in which I can turn these values into actual timestamps to compare more robustly?
CodePudding user response:
Case statements are easy to read and maintain.
for num in 5 20; do
for unit in s m h d; do
case "$unit" in
s) echo "seconds ok: $n$u" ;;
m) if (( num < 15)) then; echo "Min $num < 15 ok: $num$unit"
else echo "Min 15 , break: $num$unit" ;;
*) echo "Time > minutes, break: $num$unit" ;;
esac
done
done
output:
seconds ok: 5s
Min 5 < 15 ok: 5m
Time > minutes, break: 5h
Time > minutes, break: 5d
seconds ok: 20s
Min 15 , break: 20m
Time > minutes, break: 20h
Time > minutes, break: 20d
A simple if
structure works too.
for num in 5 20; do
for unit in s m h d; do
if [[ s == "$unit" ]] ; then echo "seconds ok: $num$unit";
elif [[ m == "$unit" ]] && (( num < 15 )) ; then echo "Min $num < 15 ok: $num$unit";
else echo "Time > 15m: $num$unit";
fi
done
done
output:
seconds ok: 5s
Min 5 < 15 ok: 5m
Time > 15m: 5h
Time > 15m: 5d
seconds ok: 20s
Time > 15m: 20m
Time > 15m: 20h
Time > 15m: 20d
I think unless a regex is pretty complicated you're going to have to break it out into multiple tests anyway, so why not keep it simple?
CodePudding user response:
#! /bin/bash
makeHorodate () {
# Initialize counters
local -i SECONDS=0
local -i MINUTES=0
local -i HOURS=0
local -i DAYS=0
# Loop on elements
for ELT in $1; do
# Remove comas
ELT=${ELT//,/}
# Check element format
[[ ! "${ELT}" =~ ^[0-9] [smhd]$ ]] && echo "oops. element '${ELT}' not recognized" >&2 && return 1
# Remove '0'
while [[ "${ELT:0:1}" == 0 ]]; do ELT=${ELT:1}; done
[[ "${ELT}" =~ ^[smhd]$ ]] && ELT="0${ELT}"
# Add values in good counter
case "${ELT}" in
*s)
SECONDS =${ELT%s}
;;
*m)
MINUTES =${ELT%m}
;;
*h)
HOURS =${ELT%h}
;;
*d)
DAYS =${ELT%d}
;;
esac
done
# Format output in a big number
local RESULT=0
printf -v RESULT "%dddd" ${DAYS} ${HOURS} ${MINUTES} ${SECONDS}
while [[ "${RESULT:0:1}" == 0 ]]; do RESULT=${RESULT:1}; done
[[ "${RESULT}" == "" ]] && RESULT=0
echo -n "${RESULT}"
return 0
}
echo $(makeHorodate "30s, 15m, 3h, 17d")
echo $(makeHorodate "44s, 23m, 17h, 5d")
# with '0'
echo $(makeHorodate "03s, 002m, 01h, 0d")
# different elements order -> same result
echo $(makeHorodate "01h, 002m, 03s, 0d")
# some values
echo $(makeHorodate "3m, 15d")
# just 15 seconds
echo $(makeHorodate "15s")
# now numeric comparisons are possible between any values
if [[ $(makeHorodate "01h, 002m, 03s, 0d") -eq $(makeHorodate "03s, 002m, 01h, 0d") ]]; then
echo "Equal"
fi
# Test > 15 seconds
if [[ $(makeHorodate "01h, 002m, 03s, 0d") -gt $(makeHorodate "15s") ]]; then
echo "> 15 seconds"
fi
# Other test for 15 seconds
if [[ $(makeHorodate "01h, 002m, 03s, 0d") -gt 15 ]]; then
echo "> 15 seconds"
fi
# Test > 3 minutes
if [[ $(makeHorodate "01h, 002m, 03s, 0d") -gt $(makeHorodate "3m") ]]; then
echo "> 3 minutes"
fi
# Other test > 3 minutes
if [[ $(makeHorodate "01h, 002m, 03s, 0d") -gt 3000 ]]; then
echo "> 3 minutes"
fi
Output:
17003015030
5017023044
1002003
1002003
15000003000
15
Equal
> 15 seconds
> 15 seconds
> 3 minutes
> 3 minutes