2021-01-25 Generating consecutive dates in Unix shell

It is no surprise for any regular reader that I have a kind of love-hate relationship with the shell. Bash is one of the most terrible languages out there, but sometimes writing a short shell snippet is just handy.

This was the case some time ago, when I wanted to loop over several dates. GNU Coreutils have the seq utility which can generate arithmetic progressions – say seq 1 5 and you’ll get

1
2
3
4
5

Now imagine that you wanted to print all dates in, say, December 2020 (believe this or not, this was exactly what I needed some time ago!). You couldn’t just say for i in $(seq 1 31); do echo 2020-12-$i; done, since then you’d get e.g. 2020-12-1 instead of 2020-12-01. Luckily, seq supports a --format argument, much like printf (but be warned, it supports much fewer options – see the manual for the details, but the point is that it only supports floating point numbers and not integers!) – for i in $(seq -f%02.f 1 31); do echo 2020-12-$i; done yields what we’re after.

Of course, now that we know about the -f option, we can get rid of the for loop altogether and say just seq -f2020-12-%02.f 1 31.

And this is all nice, but after writing it I started to wonder if there’s a better way. After all, if I needed to display the 60 consecutive days starting with 2020-11-30, or all the Sundays in 2020, I’d probably need a “proper” programming language, right?

Well, wrong. Shell (and GNU Coreutils) have you covered here, too.

At first I thought (hoped?) that the cal utility could be used for that. Alas, it can’t. However, there is another tool which excels in time/date calculations – date. After a few minutes of consulting the docs and experimenting I came up with this: for i in $(seq 0 59); do date -I -d "2020-11-15 $i days"; done How cool is that again?

Knowing that 2020-01-05 was the first Sunday of 2020, we can also display all the Sundays in that year pretty easily: for i in $(seq 0 7 36); do date -I -d "2020-01-05" $i days"; done | grep ^2020 Of course, this is not good style – we actually computed a bit more and just cut off the rest, and we had to know the date of the first Sunday in 2020 – but chill down, this is a shell, where you just can do things interactively and get to your result by trial and error. The bottom line is not that bash is Turing-complete – everyone knows that, and nobody wants to make real use of that. The bottom line is that you can quite easily use the shell, coreutils and friends to accomplish simple, one-off tasks.

CategoryEnglish, CategoryBlog