I have a text file containing birthdays:

1/23 Horace
3/1 Taraneh
7/14 Valerian
11/31 Carmen

I want to display the birthdays from today's date.
For example if today is 4/7 (April 7th):

7/14 Valerian
11/31 Carmen
1/23 Horace
3/1 Taraneh

How to do this in a bash script?

I have found how to split a text file based on a pattern (I could then concatenate the splits in the opposite order) but here the trick is that today's date might be absent, or might be the birthday of several people.

Note: all dates are valid dates.


Maybe something like:

date +'%m/%d 0000' |
  sort -nt/ -k1 -k2 - birthdays.txt |
  awk '$2 == "0000" {past_today = 1; next}
       past_today {print; next}
       {next_year = next_year $0 RS}
       END {printf "%s", next_year}'

That is, insert a 04/07 0000 line (date +%-m/%-d would output 4/7 with some date implementations but is not portable, and 04/07 works just as well) before sorting by date, and then have awk move the lines that are before that one to the end.

sort ... - birthdays.txt

sorts both its stdin (represented by -, here a pipe that is fed by date) and the content of birthdays.txt.

We set the key separator to / with -t/, -k1 specifies a sort key that runs from start to end of the line (in essence, -k1 specifies the full line as a sort key), and -k2 a sort key that starts from the first character after the first / to the end of the line, but with -n, those are interpreted as numbers, so only the initial sequence of digits matters.

(the above would work with any Bourne-like shell (including bash), no need to install bash just for that).

  • Please explain how does sort combine both the contents of birthdays.txt and the output of date piped into it in a single output. – Tulains Córdova Apr 7 '17 at 11:55
  • @TulainsCórdova, see edit. – Stéphane Chazelas Apr 7 '17 at 12:16

First change "/" in space and sort

sed 's|/| |' data | sort -k1,1n -k2,2n >out.tmp

Next, output the next dates before and the previous after

awk -v m=4 -v d=7 '$1 > m || $1 == m && $2 >= d' out.tmp
awk -v m=4 -v d=7 '$1 < m || $1 == m && $2 <  d' out.tmp
  • @NicolasRaoul: strange, it gives me the right answer. Probably a different flavour of "sort". Anyway no problem, you have an accepted answer. – enzotib Apr 7 '17 at 8:08
  • Sorry I was wrong, your answer works too, thanks! – Nicolas Raoul Apr 7 '17 at 8:57
  • This answer would benefit from an explanation how it works. – David Conrad Apr 7 '17 at 15:30

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.