2015-01-29 24 views
37

ho tale script bash:Bash: Looping attraverso date

array=('2015-01-01', '2015-01-02') 

for i in "${array[@]}" 
do 
    python /home/user/executeJobs.py {i} &> /home/user/${i}.log 
done 

Ora voglio collegare attraverso un intervallo di date, per esempio 2015-01-01 fino al 2015-01-31.

Come raggiungere in Bash?

Aggiornamento:

Nice-to-have: Nessun lavoro deve essere avviato prima di una corsa precedente è stata completata. In questo caso, quando executeJobs.py viene completato il prompt di bash $ verrà restituito.

ad es. è possibile inserire wait%1 nel mio ciclo?

+0

Sei su una piattaforma con la data GNU? –

+1

controlla questo link: http://www.glatter-gotz.com/blog/2011/02/19/looping-through-dates-in-a-bash-script-on-osx/ – qqibrow

+1

BTW, visto che hai un Interprete Python a portata di mano, questo sarebbe molto, molto più facile da fare in modo affidabile e portabile usando il modulo Python 'datetime'. –

risposta

90

Utilizzando GNU Data:

d=2015-01-01 
while [ "$d" != 2015-02-20 ]; do 
    echo $d 
    d=$(date -I -d "$d + 1 day") 
done 

Nota che a causa Questo utilizza confronto delle stringhe, richiede la notazione ISO 8601 completa delle date dei bordi (non rimuovere gli zeri iniziali). Per verificare i dati di input validi e costringere a una forma valida, se possibile, è possibile utilizzare date così:

# 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 

Un'ultima aggiunta: per controllare che $startdate è prima $enddate, se ci si aspetta solo date tra gli anni 1000 e 9999, si può semplicemente utilizzare il confronto di stringhe in questo modo:

while [[ "$d" < "$enddate" ]]; do 

Per essere sul lato molto sicuro oltre l'anno 10000, in cui il confronto lessicografico si rompe, usare

while [ "$(date -d "$d" +%Y%m%d)" -lt "$(date -d "$enddate" +%Y%m%d)" ]; do 

L'espressione $(date -d "$d" +%Y%m%d) converte $d ad una forma numerica, cioè, diventa 2015-02-2320150223, e l'idea è che date in questa forma possono essere confrontati numericamente.

+0

Stavo lavorando su questo, ma mi hai battuto. :) –

+0

BTW, è possibile evitare il bug con loop infinito quando il formato della data non è esatto eseguendo la pre-elaborazione della data di fine nel codice in modo che corrisponda al formato di output del comando 'date'. (Disattivare quando quel comando non ha successo è, analogamente, meglio di un ciclo infinito su input errati). –

+0

@CharlesDuffy Molto semplicemente con '$ (data -I -d" $ enddate ")', sì. Sarebbe una buona idea se le date provengano da input dell'utente/fonti non attendibili (come verrebbe in seguito il controllo di '$? '). – Wintermute

8

Brace expansion:

for i in 2015-01-{01..31} … 

Più:

for i in 2015-02-{01..28} 2015-{04,06,09,11}-{01..30} 2015-{01,03,05,07,08,10,12}-{01..31} … 

Dimostrazione:

$ 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/nidificato:

$ echo 2015-{02-{01..28},{04,06,09,11}-{01..30},{01,03,05,07,08,10,12}-{01..31}} | wc -w 
365 

ordinato, se è importante:

$ x=($(printf '%s\n' 2015-{02-{01..28},{04,06,09,11}-{01..30},{01,03,05,07,08,10,12}-{01..31}} | sort)) 
$ echo "${#x[@]}" 
365 

Dal momento che è ordinata, si può semplicemente virare anni bisestili 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 
+1

Che dire degli anni bisestili? – Wintermute

+0

Posso quindi usare 'python /home/user/executeJobs.py 2015-01- {01..31} &>/home/user/2015-01- {01..31} .log'? – nottinhill

+0

@SirBenBenji Dipende da 'executeJobs.py'. – kojiro

0

Se si vuole ciclo a partire dalla data di ingresso a qualsiasi intervallo di seguito può essere utilizzato, anche esso stamperà output in formato aaaaMMgg ...

#!/bin/bash 
in=2018-01-15 
while [ "$in" != 2018-01-25 ]; do 
    in=$(date -I -d "$in + 1 day") 
    x=$(date -d "$in" +%Y%m%d) 
    echo $x 
done 
Problemi correlati