2009-10-27 12 views
9

Sto provando a creare uno script che esegua il loop dei file con i nomi dei file scritti nel seguente formato: yyyymmdd.hh.filename.loop di bash tra due date date

Lo script viene chiamato con:

./loopscript.sh 20091026.00 23 
./loopscript.sh 20091026.11 15 
./loopscript.sh 20091026.09 20091027.17 

La necessità è per lo script per controllare ogni ora tra queste due date/ore.

ad es.

cat 20091026.00.filename |more 
cat 20091026.01.filename |more 
... 
cat 20091026.23.filename |more 
cat 20091027.01.filename |more 
cat 20091027.02.filename |more 
... 

e così via.

qualche idea su come procedere? Non ho alcuna difficoltà con i cicli standard 0 - x. o semplice per loops. Non so come andare su quanto sopra.

+0

uso inutile di 'cat': basta usare' più nomefile' –

risposta

5

Per elaborare ogni file tra due certa data/ora, è possibile utilizzare il seguente:

#!/usr/bin/bash 
#set -x 

usage() { 
    echo 'Usage: loopscript.sh <from> <to>' 
    echo '  <from> MUST be yyyymmdd.hh or empty, meaning 00000000.00' 
    echo '  <to> can be shorter and is affected by <from>' 
    echo '   e.g., 20091026.00  27.01 becomes' 
    echo '    20091026.00 20091027.01' 
    echo '   If empty, it is set to 99999999.99' 
    echo 'Arguments were:' 
    echo " '${from}'" 
    echo " '${to}'" 
} 

# Check parameters. 

from="00000000.00" 
to="99999999.99" 
if [[ ! -z "$1" ]] ; then 
    from=$1 
fi 
if [[ ! -z "$2" ]] ; then 
    to=$2 
fi 
## Insert this to default to rest-of-day when first argument 
## but no second argument. Basically just sets second 
## argument to 23 so it will be transformed to end-of-day. 
#if [[ ! -z "$1"]] ; then 
# if [[ -z "$2"]] ; then 
#  to=23 
# fi 
#fi 

if [[ ${#from} -ne 11 || ${#to} -gt 11 ]] ; then 
    usage 
    exit 1 
fi 

# Sneaky code to modify a short "to" based on the start of "from". 
# ${#from} is the length of ${from}. 
# $((${#from}-${#to})) is the length difference between ${from} and ${to} 
# ${from:0:$((${#from}-${#to}))} is the start of ${from} long enough 
# to make ${to} the same length. 
# ${from:0:$((${#from}-${#to}))}${to} is that with ${to} appended. 
# Voila! Easy, no? 

if [[ ${#to} -lt ${#from} ]] ; then 
    to=${from:0:$((${#from}-${#to}))}${to} 
fi 

# Process all files, checking that they're inside the range. 

echo "From ${from} to ${to}" 
for file in [0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9].[0-9][0-9].* ; do 
    if [[ ! (${file:0:11} < ${from} || ${file:0:11} > ${to}) ]] ; then 
     echo " ${file}" 
    fi 
done 

Quando si creano i file 20091026.00.${RANDOM} attraverso 20091028.23.${RANDOM} incluso, questo è un paio di esecuzioni campione:

pax> ./loopscript.sh 20091026.07 9 
From 20091026.07 to 20091026.09 
    20091026.07.21772 
    20091026.08.31390 
    20091026.09.9214 
pax> ./loopscript.sh 20091027.21 28.02 
From 20091027.21 to 20091028.02 
    20091027.21.22582 
    20091027.22.30063 
    20091027.23.29437 
    20091028.00.14744 
    20091028.01.6827 
    20091028.02.10366 
pax> ./loopscript.sh 00000000.00 99999999.99 # or just leave off the parameters. 
    20091026.00.25772 
    20091026.01.25964 
    20091026.02.21132 
    20091026.03.3116 
    20091026.04.6271 
    20091026.05.14870 
    20091026.06.28826 
    : : : 
    20091028.17.20089 
    20091028.18.13816 
    20091028.19.7650 
    20091028.20.20927 
    20091028.21.13248 
    20091028.22.9125 
    20091028.23.7870 

Come si può vedere, il primo argomento deve essere del formato corretto yyyymmdd.hh. Il secondo argomento può essere più breve poiché eredita l'inizio del primo argomento per renderlo la lunghezza corretta.

Questo solo tenta di elaborare i file esistenti (da ls) e del formato corretto, non ogni data/ora all'interno dell'intervallo. Ciò sarà più efficiente se si dispone di file sparsi (compresi all'inizio e alla fine dell'intervallo) poiché non è necessario verificare che i file esistano.

Tra l'altro, questo è il comando che ha creato i file di prova, se siete interessati:

pax> for dt in 20091026 20091027 20091028 ; do 
     for tm in 00 01 02 ... you get the idea ... 21 22 23 ; do 
      touch $dt.$tm.$RANDOM 
     done 
    done 

Si prega di non digitare che nella parola per parola e poi si lamentano che ha creato i file come:

20091026.you.12345 
20091028.idea.77 

ho solo tagliati lungo la linea di modo che si inserisce nella larghezza di codice. :-)

+0

wow, sono stupefatto delle risposte. Tornerò a voi. – Chasester

+0

se qualcuno immette ./loopscript.sh 20091026.07 senza un valore. Funzionerà dal 20091026.07 al 20091023.07 c'è un modo per impostarlo su .23? Ho questo per la parte superiore del codice -ripetenza per impostare la data corrente come ora di st/fine da = "$ (data +% Y) $ (data +% m) $ (data +% d)" .00 " a =" $ (data +% Y) $ (data +% m) $ (data +% d) ". 23" se [[! -z "$ 2"]]; poi da = $ 2 fi se [[! -z "$ 3"]]; quindi a = $ 3 fi se [[$ {# from} -ne 11 || $ {# a} -gt 11]]; quindi utilizzo uscita 1 fi se [[$ {# a} -lt $ {# da}]]; quindi da a = $ {da: 0: $ (($ {# da} - $ {# a})} $ {a} fi – Chasester

+0

Invece dei tuoi primi due test, basta fare il terzo test sui parametri posizionali direttamente: '$ {# 1}' seguito da assegnazioni come: 'from = $ {1: -00000000.00}'. Creazione del ciclo interno dei file di test: 'for tm in 0 {0..24}; tocca $ dt. $ {tm: -2}. $ RANDOM; done' o senza un ciclo interno: 'tocca $ dt.0 {0..9}. $ RANDOM; toccare $ dt. {10..19}. $ RANDOM; tocca $ dt. {20..23}. $ RANDOM' –

1

Una possibile soluzione: convertire le date nella rappresentazione Unix standard di "Secondi passati dall'epoca" e ciclo, aumentando questo numero di 3600 (numero di secondi in un'ora) ogni iterazione. Esempio:

#!/bin/bash 

# Parse your input to date and hour first, so you get: 
date_from=20090911 
hour_from=10 
date_to=20091026 
hour_to=01 

i=`date --date="$date_from $hour_from:00:00" +%s` 
j=`date --date="$date_to $hour_to:00:00" +%s` 

while [[ $i < $j ]]; do 
    date -d "1970-01-01 $i sec" "+%Y%m%d.%H" 
    i=$[ $i + 3600 ] 
done 
+0

suggeriscono che ci sono 3600 secondi all'ora - e l'incremento di ore come richiesto. –

+0

Questo codice fa poche ore di differenza a causa del fuso orario. – kachar

23

ne dite di questo:

#!/bin/bash 

date1=$1 
date2=$2 

#verify dates 
if ! date -d "$date1" 2>&1 > /dev/null ; 
    then echo "first date is invalid" ; exit 1 
fi 
if ! date -d "$date2" 2>&1 > /dev/null ; 
    then echo "second date is invalid" ; exit 1 
fi 

#set current and end date 
current=$(date -d "$date1") 
end=$(date -d "$date2 +1 hours") 

#loop over all dates 
while [ "$end" != "$current" ] 
do 
    file=$(date -d "$current" +%Y%m%d.%H) 
    cat $file."filename" | more 
    current=$(date -d "$current +1 hours") 
done 
+0

Questo è ragionevole per le date ma non gestisce affatto le ore. In realtà, è un po 'sospetto anche per gli appuntamenti - se gli dai il 20091027 e il 20091028, ottieni dal 20091027,00 al 20091028.00 - Mi aspetterei che si fermasse a 1027.23 o 1028.23. – paxdiablo

+0

Gestisce le ore se lo chiamate con "20091027 00" "20091028 03", ha dimenticato di dirlo. – Puppe

+0

Aaah, è meglio. Presumibilmente è la data di fare il lavoro da grugnito. Non male. – paxdiablo