Probar si el archivo se modificó después de la fecha en el nombre del archivo


11

Tengo un archivo con YYYYMMDDel nombre del archivo, como

file-name-20151002.txt

Quiero determinar si este archivo se modificó después del 02/10/2015.

Notas:

  • Puedo hacer esto mirando la salida de ls, pero sé que analizar la salida de lses una mala idea.
  • No necesito encontrar todos los archivos con fecha posterior a una fecha específica, solo necesito probar un archivo específico a la vez.
  • No me preocupa que el archivo se modifique en la misma fecha después de haberlo creado. Es decir, solo quiero saber si este archivo con 20151002el nombre se modificó el 03 de octubre de 2015 o posterior.
  • Estoy en MacOs 10.9.5.

Disculpas por no incluir el sistema operativo antes.
Peter Grill

Respuestas:


4

Aquí hay algunas formas posibles con:

  • OSX stat:

    newer () {
    tstamp=${1:${#1}-12:8}
    mtime=$(stat -f "%Sm" -t "%Y%m%d" "$1")
    [[ ${mtime} -le ${tstamp} ]] && printf '%s\n' "$1 : NO: mtime is ${mtime}" || printf '%s\n' "$1 : YES: mtime is ${mtime}"
    }
  • GNU date:

    newer () {
    tstamp=${1:${#1}-12:8}
    mtime=$(date '+%Y%m%d' -r "$1")
    [[ ${mtime} -le ${tstamp} ]] && printf '%s\n' "$1 : NO: mtime is ${mtime}" || printf '%s\n' "$1 : YES: mtime is ${mtime}"
    }
  • zsh solamente:

    zmodload zsh/stat
    newer () {
    tstamp=${1:${#1}-12:8}
    mtime=$(zstat -F '%Y%m%d' +mtime -- $1)
    [[ ${mtime} -le ${tstamp} ]] && printf '%s\n' "$1 : NO: mtime is ${mtime}" || printf '%s\n' "$1 : YES: mtime is ${mtime}"
    }

Uso:

nuevo archivo

Salida de ejemplo:

file-name-20150909.txt : YES: mtime is 20151026

o

file-name-20151126.txt : NO: mtime is 20151026

9

El siguiente script verificará las fechas de todos los archivos especificados en la línea de comando:

Se requiere versiones GNU de sed, dateystat

$ cat check-dates.sh 
#! /bin/bash

for f in "$@" ; do
  # get date portion of filename
  fdate=$(basename "$f" .txt | sed -re 's/^.*(2015)/\1/')

  # convert it to seconds since epoch + 1 day
  fsecs=$(echo $(date +%s -d "$fdate") + 86400 | bc )

  # get modified timestamp of file in secs since epoch
  ftimestamp=$(stat -c %Y "$f")

  [ "$ftimestamp" -gt "$fsecs" ] && echo "$f has been modified after $fdate"
done

$ ./check-dates.sh file-name-20151002.txt 
file-name-20151002.txt has been modified after 20151002
$ ls -l file-name-20151002.txt 
-rw-rw-r-- 1 cas cas 0 Oct 26 19:21 file-name-20151002.txt

Aquí hay una versión que no se ha probado pero que debería funcionar en Mac (y en FreeBSD, etc.) si he leído las páginas de manual en línea correctamente:

#! /bin/bash

for f in "$@" ; do
  # get date portion of filename
  fdate=$(basename "$f" .txt | sed -e 's/^.*\(2015\)/\1/')

  # convert it to seconds since epoch + 1 day
  fsecs=$(echo $(date -j -f %Y%m%d "$fdate" +%s) + 86400 | bc )

  # get modified timestamp of file in secs since epoch
  ftimestamp=$(stat -f %m "$f")

  [ "$ftimestamp" -gt "$fsecs" ] && echo "$f has been modified after $fdate"
done

Una solución aún mejor sería una que no requiera 4-5 extensiones frente a POSIX.
Thomas Dickey

2
Siéntase libre de escribir su propia versión, entonces. Escribo lo que quiero escribir, no lo que quieres que escriba ... y eso incluye el uso de versiones GNU de herramientas. OMI, GNU ES el estándar de facto. y los números relativos de distribuciones de linux en uso frente a non-linux, non-gnu * nixes lo admiten.
cas

66
@cas: una respuesta bastante dura al comentario de Thomas que fue, creo, solo una sugerencia para mejorar su solución ... En el mundo real, tener el script "lo más estándar posible" no es solo una ventaja, sino que es necesario (o más bien, obligatorio). Muchos lugares no pueden instalar la versión GNU de las herramientas (resulta que conozco 3 lugares diferentes donde algunos de los últimos vers de bash del sistema son 2.xy awk es tan antiguo que está muy, muy cerca del original). Las necesidades de esta pregunta probablemente no son "críticas" (pero podrían serlo) y tampoco son buscadas / utilizadas por otras personas, pero en general, tener una solución portátil es un +
Olivier Dulac

Me estoy poniendo sed: illegal option -- rcon MacOS 10.9.5.
Peter Grill

-res una sedopción de GNU para decirle que use expresiones regulares extendidas. Puede cambiar el script sed para usar regexp básico en lugar de extendido (p. Ej., sed -e 's/^.*\(2015\)/\1/')Pero el resto del script probablemente todavía fallará porque requiere las versiones GNU de datey stat, y no creo que las Mac vengan con ellos de forma estándar (aunque son disponible para Mac en paquetes precompilados)
cas

4

El uso de bash y staty exprpara obtener las fechas como números y compararlos:

#!/bin/bash
for file
do  moddate=$(stat -f %m -t %F "$file") # MacOS stat
    moddate=${moddate//-/} # 20151026
    if filedate=$(expr "$file" : '.*-\([0-9]*\).txt')
    then  if [ $moddate -gt $filedate ]
          then echo "$file: modified $moddate"
          fi
    fi
done

Esta fue mi respuesta anterior específica de Linux.

#!/bin/bash
for file
do  moddate=$(stat -c %y "$file")
    moddate=${moddate%% *} # 2015-10-26
    moddate=${moddate//-/} # 20151026
    if [[ "$file" =~ ([0-9]{8}).txt$ ]]
    then  if [[ $moddate > ${BASH_REMATCH[1]} ]]
          then echo "$file: modified $moddate"
          fi
    fi
done

El =~operador bash regexp captura los 8 dígitos del nombre del archivo en la matriz bash BASH_REMATCH. [[ ]]compara las cadenas, aunque simplemente las compara como números en su lugar [ -gt ].


MacOS 10.9.5 no parece tener la -copción de hacerlo stat.
Peter Grill

Culpa mía. El equivalente parece ser stat -f %m -t %F "$file". Lo siento, no puedo probarlo.
meuh

Con el cambio en el statsegún su comentario, las cosas parecen ejecutarse pero no hay salida para todos los casos de prueba. Pero, ¿qué está "$file" =~ ([0-9]{8}).txt$haciendo?
Peter Grill

Busca los 8 dígitos seguidos .txtal final del nombre del archivo. El paréntesis ()captura la parte de 8 dígitos, y puede encontrarlo en ${BASH_REMATCH[1]}.
meuh

Si su bash no funciona if [[=~]], puede probar el básico if filedate=$(expr "$file" : '.*-\([0-9]*\).txt')y luego reemplazarlo ${BASH_REMATCH[1]}por $filedate.
meuh

4

Podrías hacer esto:

  • extraer los valores de año / mes / día en una variable de shell,
  • crear un archivo temporal
  • use el touchcomando (agregando 0s por hora / minuto / segundo) para establecer la fecha de modificación para el archivo temporal

Debido a que su pregunta es sobre bash, es probable que esté utilizando Linux. El testprograma utilizado en Linux (parte de coreutils ) tiene extensiones para la comparación de marcas de tiempo ( -nty -ot) que no se encuentran en POSIXtest .

POSIX comenta sobre esto en la justificación de test:

Algunas primarias adicionales recién inventadas o de KornShell aparecieron en una propuesta inicial como parte del comando condicional ( [[]]): s1> s2, s1 <s2, str = pattern, str! = Pattern, f1 -nt f2, f1 -ot f2, y f1 -ef f2. No se transfirieron a la utilidad de prueba cuando el comando condicional se eliminó del shell porque no se han incluido en la utilidad de prueba integrada en implementaciones históricas de la utilidad sh.

Usando esa extensión, podrías

  • cree otro archivo temporal con la fecha con la que desea comparar
  • use el -ntoperador testpara hacer la comparación que solicitó.

Aquí hay un ejemplo. Una aclaración de OP mencionó la plataforma, por lo que uno podría usar statcomo alternativa a los archivos temporales (compare OSX y Linux ):

#!/bin/bash
# inspect each file...

with_tempfile() {
    echo "** with temporary file $name"
    test=$MYTEMP/$name
    touch -t $date $test
    [ $name -nt $test ] && echo "...newer"
}

# alternatively (and this is system-dependent)
with_stat() {
    echo "** with stat command $name"
    stat=$(stat -t "%Y%m%d%H%M" -f "%Sm" $name)
    [ $stat -gt $date ] && echo "...newer"
}

MYTEMP=$(mktemp -d /var/tmp/isnewer.XXXXXX)
trap "rm -rf $MYTEMP" EXIT
for name in file-name-[0-9][0-9]*.txt
do
    if [ -f "$name" ];
    then
            date=${name%%.txt}
            date=${date/file-name-}
            date=${date//-/}2359
            with_tempfile $name
            with_stat $name
    fi
done

Al crear archivos temporales, es una práctica estándar eliminar los archivos pasados ​​por alto con un trapcomando.
Thomas Dickey

Estoy en MacOS 10.9.5.
Peter Grill

Gracias por la aclaración. Los archivos temporales no son tan elegantes como algunos enfoques posibles que dependen de extensiones adicionales, pero proporcionaré una secuencia de comandos de muestra corta, para mantener la coherencia.
Thomas Dickey

1

Otro zshenfoque:

zmodload zsh/stat # best in ~/.zshrc or
zmodload -F zsh/stat +b:zstat # to avoid overriding an eventual
                              # system stat command.
setopt extendedglob # best in ~/.zshrc

ls -ld -- **/*[0-9](#c8)*(De@'zstat -F %Y%m%d -A m +mtime $REPLY &&
  [[ ${(SM)${REPLY:t}#[0-9](#c8)} != $m ]]'@)

Informaría los archivos que tienen algo que parece una marca de tiempo en su nombre pero que no corresponde a su última hora de modificación.

zshtiene una gran cantidad de operadores como ese para manipular globos y variables. Es muy útil hacer cualquier trabajo rápidamente (y generalmente de manera confiable), pero es bastante difícil entenderlos a todos y a menudo produce lo que generalmente llamamos código de solo escritura (eufemismo para código ilegible, aunque también implica que no lo haga) No es necesario leerlo mientras lo escribe para un solo uso en el símbolo del sistema)

Un recorrido rápido por:

  • **/pattern(qualifier): glob recursivo con calificador glob.
  • [0-9](#c8)coincide con 8 dígitos. Ese es el equivalente de zsh extendedglob de ksh's {8}([0-9]).
  • D: incluye archivos ocultos
  • e@...@: el calificador eval glob para ejecutar algún texto para calificar aún más los archivos. Ruta de archivo pasada$REPLY
  • zstat...recupere el mtime formateado como AAAAMMDD en la $mmatriz.
  • ${REPLY:t}: se expande a la cola t (el nombre base) del archivo.
  • ${(SM)something#pattern}. Extraiga el patrón de coincidencia de parte de algo . Esos S( búsqueda de S ubstring) y M(expandir a la porción M atched) se denominan banderas de expansión de parámetros .
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.