I have such bash script:
array=( '2015-01-01', '2015-01-02' )
for i in "${array[@]}"
do
python /home/user/executeJobs.py {i} &> /home/user/${i}.log
done
Now I want to loop through a range of dates, e.g. 2015-01-01 until 2015-01-31.
How to achieve in Bash?
Update:
Nice-to-have: No job should be started before a previous run has completed. In this case, when executeJobs.py is completed bash prompt $
will return.
e.g. could I incorporate wait%1
in my loop?
Using GNU date:
d=2015-01-01
while [ "$d" != 2015-02-20 ]; do
echo $d
d=$(date -I -d "$d + 1 day")
# mac option for d decl (the +1d is equivalent to + 1 day)
# d=$(date -j -v +1d -f "%Y-%m-%d" $d +%Y-%m-%d)
done
Note that because this uses string comparison, it requires full ISO 8601 notation of the edge dates (do not remove leading zeros). To check for valid input data and coerce it to a valid form if possible, you can use date
as well:
# slightly malformed input data
input_start=2015-1-1
input_end=2015-2-23
# After this, startdate and enddate will be valid ISO 8601 dates,
# or the script will have aborted when it encountered unparseable data
# such as input_end=abcd
startdate=$(date -I -d "$input_start") || exit -1
enddate=$(date -I -d "$input_end") || exit -1
d="$startdate"
while [ "$d" != "$enddate" ]; do
echo $d
d=$(date -I -d "$d + 1 day")
done
One final addition: To check that $startdate
is before $enddate
, if you only expect dates between the years 1000 and 9999, you can simply use string comparison like this:
while [[ "$d" < "$enddate" ]]; do
To be on the very safe side beyond the year 10000, when lexicographical comparison breaks down, use
while [ "$(date -d "$d" +%Y%m%d)" -lt "$(date -d "$enddate" +%Y%m%d)" ]; do
The expression $(date -d "$d" +%Y%m%d)
converts $d
to a numerical form, i.e., 2015-02-23
becomes 20150223
, and the idea is that dates in this form can be compared numerically.
Brace expansion:
for i in 2015-01-{01..31} …
More:
for i in 2015-02-{01..28} 2015-{04,06,09,11}-{01..30} 2015-{01,03,05,07,08,10,12}-{01..31} …
Proof:
$ echo 2015-02-{01..28} 2015-{04,06,09,11}-{01..30} 2015-{01,03,05,07,08,10,12}-{01..31} | wc -w
365
Compact/nested:
$ echo 2015-{02-{01..28},{04,06,09,11}-{01..30},{01,03,05,07,08,10,12}-{01..31}} | wc -w
365
Ordered, if it matters:
$ x=( $(printf '%s\n' 2015-{02-{01..28},{04,06,09,11}-{01..30},{01,03,05,07,08,10,12}-{01..31}} | sort -n -t"-" -k1 -k2 -k3) )
$ echo "${#x[@]}"
365
Since it's unordered, you can just tack leap years on:
$ echo {2015..2030}-{02-{01..28},{04,06,09,11}-{01..30},{01,03,05,07,08,10,12}-{01..31}} {2016..2028..4}-02-29 | wc -w
5844
start='2019-01-01'
end='2019-02-01'
start=$(date -d $start +%Y%m%d)
end=$(date -d $end +%Y%m%d)
while [[ $start -le $end ]]
do
echo $(date -d $start +%Y-%m-%d)
start=$(date -d"$start + 1 day" +"%Y%m%d")
done
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With