2

I have 2 dates, start=20190903 & end=20210912 and want to increment till start approaches the end, increment is 13 days.

have following code, but it exceeds end.

#! /usr/bin/env bash

start="20190903"
end="20210912"

startdate="$(date -d ${start} +'%Y-%m-%d')"
enddate="$(date -d ${end} +'%Y-%m-%d')"
echo ${startdate}
echo ${enddate}

while [ "${startdate}" < "${enddate}" ]; do
    echo ${startdate}
    startdate="$( date -d "${startdate} + 13 days" +'%Y-%m-%d')"
done
4
  • 1
    didn't bash complain about no such file named 2021-09-12? Oct 3 at 11:46
  • @UncleBilly it didn't, it kept printing beyond end date. Or gave error about unary operation etc
    – Sollosa
    Oct 3 at 11:52
  • 2
    or didn't you consider "relevant"? anyways, just using double brackets while [[ ... ]] will probably fix your script. Oct 3 at 11:52
  • 2
    then it's most likely that you created such a file when you used > instead of < in a previous version of the script ;-) Oct 3 at 12:19
5

By comparing the startdate+interval with the end you prevent exeeding it.

#!/bin/bash

start="20190903"
end="20210912"
interval=1123200
    # 13 days = 13 * 24 * 60 *60

startdate=$( date --utc -d ${start} +%s )
enddate=$( date --utc -d ${end} +%s )

echo "$( date --utc -d @${startdate} +"%Y-%m-%d" ) (start)"
next=${startdate}
while [[ "$(( next+interval ))" -lt "${enddate}" ]] ; do
    next=$(( next+interval ))
    nextdate=$( date --utc -d @${next} +"%Y-%m-%d" )
    echo "${nextdate}"
done
echo "$( date --utc -d @${enddate} +"%Y-%m-%d" ) (end)"

I was not sure about your way of adding 13 days, so I changed it to seconds since 1970-01-01. At least now you know of another way of doing it.

2
  • 4
    Your interval in seconds isn't quite the same as + 13 days. In a timezone on or near UTC that switches between summer time and winter time you could possibly end up reaching the 13 day interval either an hour early or an hour late. If you're going to use an absolute value it's worth treating dates as having midnight UTC (i.e. using date --utc)
    – roaima
    Oct 3 at 22:55
  • 1
    I added --utc to deal with that. Thx, for pointing it out
    – poinck
    Oct 5 at 13:08
3

To expand on Uncle Billy's comments, [ is a regular command, so your use of < is standard input redirection. If you didn't get a bash: line 9: 2021-09-12: No such file or directory error, it's likely that you had created that file with a previous use of >. If that's the case, then

[ "${startdate}" < "${enddate}" ]

evaluates the same as

[ "${startdate}" ]

which is truthy as long as $startdate is not unset or empty. So, you have an infinite loop.

Changing to using [[ as in

while [[ "${startdate}" < "${enddate}" ]]; do

fixes this because that's a special form with its own syntax instead of a regular command and </> aren't parsed as redirections then.

EDIT: [[ is a bash-ism. If you want this to work with [ so it's POSIX-compatible, you could use -lt. However, since that does numerical comparison instead of lexicographical like < does, you'd have to remove the -s from your date format:

#!/bin/sh

startdate="20190903"
enddate="20210912"

echo ${startdate}
echo ${enddate}

while [ "${startdate}" -lt "${enddate}" ]; do
    echo ${startdate}
    startdate="$( date -d "${startdate} + 13 days" +'%Y%m%d')"
done

In your case, with such a change, you end up with less code, since you no longer need to turn start into startdate and same with end/enddate.

EDIT 2: Another option seems to be to escape < as in [ "${startdate}" \< "${enddate}" ], but that seems to only work for bash. It's not POSIX and it fails on zsh, at least.

8
  • 1
    Or use -gtand -lt for that POSIX feeling
    – roaima
    Oct 3 at 22:56
  • 1
    @roaima Yes, though that would require a bigger change like poinck's to use Unix timestamps instead of ISO.
    – JoL
    Oct 4 at 15:43
  • You could also use '<' or \< within [ ... ].
    – they
    Oct 4 at 16:04
  • @zevzek True, and they end up with less lines, too. Good call. I've edited the answer.
    – JoL
    Oct 4 at 16:11
  • @they I didn't realize bash supported that, but it seems only bash does.
    – JoL
    Oct 4 at 16:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.