2009-10-27 11 views
9

Estoy tratando de crear una secuencia de comandos que recorra los archivos que tienen sus nombres de archivo escritos en el siguiente formato: aaaammdd.hh.nombre de archivo.bash loop entre dos fechas dadas

El script se llama con:

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

La necesidad es para la secuencia de comandos para comprobar cada hora entre esas dos fechas/horas dadas.

p. Ej.

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 
... 

y así sucesivamente.

¿Alguna idea de cómo hacerlo? No tengo ninguna dificultad con 0 - x loops estándar. o simple para bucles. Simplemente no estoy seguro de cómo hacerlo.

+0

Uso inútil de 'cat': simplemente use' más nombre de archivo' –

Respuesta

5

Para procesar cada archivo entre dos fecha/hora determinada, puede utilizar lo siguiente:

#!/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 

Al crear los archivos 20091026.00.${RANDOM} a través de 20091028.23.${RANDOM} inclusive, este es un par de ejecuciones de muestra:

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 

Como puede ver, el primer argumento debe tener el formato correcto yyyymmdd.hh. El segundo argumento puede ser más corto ya que hereda el inicio del primer argumento para que sea la longitud correcta.

Esto solo intenta procesar los archivos que existen (de ls) y del formato correcto, no cada fecha/hora dentro del rango. Esto será más eficiente si tiene archivos dispersos (incluidos al principio y al final del rango) ya que no necesita verificar que los archivos existen.

Por cierto, este es el comando que creó los archivos de prueba, si está interesado:

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 

Por favor, no escriba que literalmente en el documento y luego se quejan de que los archivos creados como:

20091026.you.12345 
20091028.idea.77 

sólo arreglada abajo de la línea para que se ajuste en el ancho de código. :-)

+0

wow Estoy impresionado con las respuestas. Regresaré a ti. – Chasester

+0

si alguien ingresa ./loopscript.sh 20091026.07 sin un valor a. se ejecutará desde 20091026.07 a 20091023.07 ¿hay alguna forma de darle un valor predeterminado a .23? Tengo esto para la parte superior del código -intentar establecer la fecha actual como el st/end times from = "$ (date +% Y) $ (date +% m) $ (date +% d)" .00 " to =" $ (date +% Y) $ (date +% m) $ (date +% d) ". 23" if [[! -z "$ 2"]]; luego desde = $ 2 fi if [[! -z "$ 3"]]; luego a = $ 3 fi si [[$ {# from} -ne 11 || $ {# a} -gt 11]]; luego uso exit 1 fi if [[$ {# to} -lt $ {# from}]]; luego to = $ {from: 0: $ (($ {# from} - $ {# to}))} $ {to} fi – Chasester

+0

En lugar de sus primeras dos pruebas, simplemente haga la tercera prueba en los parámetros posicionales directamente: '$ {# 1}' seguido de asignaciones como: 'from = $ {1: -00000000.00}'. Creando el bucle interno de los archivos de prueba: 'para tm en 0 {0..24}; toca $ dt. $ {tm: -2}. $ RANDOM; done' o sin un bucle interno: 'touch $ dt.0 {0..9}. $ RANDOM; toque $ dt. {10..19}. $ RANDOM; toque $ dt. {20..23}. $ RANDOM' –

1

Una posible solución: convierta las fechas en la representación estándar de Unix de "Segundos pasados ​​desde la época" y el ciclo, aumentando este número en 3600 (número de segundos en una hora) en cada iteración. Ejemplo:

#!/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

Sugiera que haya 3600 segundos por hora y que se incrementen en horas según lo solicitado. –

+0

Este código hace pocas horas de diferencia debido a la zona horaria. – kachar

23

¿Qué tal esto:

#!/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

Esto es razonable para las fechas pero no maneja las horas en absoluto. De hecho, también es un poco sospechoso para las fechas; si le das los argumentos 20091027 y 20091028, obtienes desde 20091027.00 hasta 20091028.00, esperaría que se detuviera en 1027.23 o 1028.23. – paxdiablo

+0

Maneja horas si lo llamas con "20091027 00" "20091028 03", se olvidó de mencionar eso. – Puppe

+0

Aaah, eso es mejor. Presumiblemente esa es la fecha haciendo el trabajo duro. No está mal. – paxdiablo