简体   繁体   中英

Randomly loop over days in bash-script

At the moment, I have a while-loop that takes a starting date, runs a python script with the day as the input, then takes the day + 1 until a certain due date is reached.

day_start=2016-01-01

while [ "$day_start"!=2018-01-01 ] ; 
do
    day_end=$(date +"%Y-%m-%d" -d "$day_start + 1 day")
    python script.py --start="$day_start" --end="$day_end";
    day_start=$(date +"%Y-%m-%d" -d "$day_start + 1 day")
done

I would like to do the same thing, but now to pick a random day between 2016-01-01 and 2018-01-01 and repeat until all days have been used once. I think it should be a for-loop instead of this while loop, but I have trouble to specify the for-loop over this date-range in bash. Does anyone have an idea how to formulate this?

It can take quite a long time if you randomly choose the dates because of the Birthday Problem . (You'll hit most of the dates over and over again but the last date can take quite some time).

The best idea I can give you is this:

  • Create all dates as before in a while loop (only the day_start-line)
  • Output all dates into a temporary file
  • Use sort -R on this file ("shuffles" the contents and prints the result)
  • Loop over the output from sort -R and you'll have dates randomly picked until all were reached.

Here's an example script which incorporates my suggestions:

#!/bin/bash
day_start=2016-01-01
TMPFILE="$(mktemp)"
while [ "$day_start" != "2018-01-01" ] ;
do
  day_start=$(date +"%Y-%m-%d" -d "$day_start + 1 day")
  echo "${day_start}"
done > "${TMPFILE}"

sort -R "${TMPFILE}" | while read -r day_start
do
  day_end=$(date +"%Y-%m-%d" -d "$day_start + 1 day")
  python script.py --start="$day_start" --end="$day_end";
done
rm "${TMPFILE}"

By the way, without the spaces in the while [ "$day_start" != "2018-01-01" ]; , bash won't stop your script.

Fortunately, from 16 to 18 there was no leap year (or was it, and it just works because of that)?

  • Magic number: 2*365 = 730

The i % 100, just to have less output.

for i in {0..730}; do nd=$(date -d "2016/01/01"+${i}days +%D); if (( i % 100 == 0 || i == 730 )); then echo $nd ; fi; done 
01/01/16
04/10/16
07/19/16
10/27/16
02/04/17
05/15/17
08/23/17
12/01/17
12/31/17

With the format instruction (here +%D), you might transform the output to your needs, date --help helps.

In a better readable format, and with +%F:

for i in {0..730}
do 
  nd=$(date -d "2016/01/01"+${i}days +%F)
  echo $nd
done 

2016-01-01
2016-04-10
2016-07-19
...

For a random distribution, use shuf (here, for bevity, with 7 days):

for i in {0..6}; do nd=$(date -d "2016/01/01"+${i}days +%D); echo $nd ;done | shuf

01/04/16
01/07/16
01/05/16
01/01/16
01/03/16
01/06/16
01/02/16

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM