Teste se o arquivo foi modificado após a data no nome do arquivo

11

Eu tenho arquivos nomeados com YYYYMMDD no nome do arquivo, como

file-name-20151002.txt

Eu quero determinar se o arquivo foi modificado depois de 2015-10-02.

Notas:

  • Eu posso fazer isso olhando a saída de ls , mas sei que analisar a saída de ls é uma má ideia.
  • Eu não preciso encontrar todos arquivos datados após uma data específica, só preciso testar um arquivo específico por vez.
  • Não estou preocupado com a modificação do arquivo na mesma data depois de criá-lo. Ou seja, eu só quero saber se esse arquivo com 20151002 no nome foi modificado em 03 de outubro de 2015 ou mais tarde.
  • Eu estou no MacOs 10.9.5.
por Peter Grill 26.10.2015 / 09:10

5 respostas

4

Aqui estão algumas maneiras possíveis com:

  • 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 apenas:

    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:

newer FILE

Exemplo de saída:

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

ou

file-name-20151126.txt : NO: mtime is 20151026
    
por 26.10.2015 / 09:58
9

O script a seguir verificará as datas de todos os arquivos especificados na linha de comando:

Requer versões GNU de sed , date e stat

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

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

  # 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

Aqui está uma versão que não foi testada, mas deve funcionar em Macs (e no FreeBSD, etc.) se eu tiver lido as páginas man on-line corretamente:

#! /bin/bash

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

  # 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
    
por 26.10.2015 / 09:33
4

Usando bash e stat e expr para obter as datas como números e compará-las:

#!/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 foi a minha resposta anterior específica do 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

O operador bash =~ regexp captura os 8 dígitos do nome do arquivo na matriz bash BASH_REMATCH. [[ ]] compara as strings, embora você simplesmente os compara como números em vez de [ -gt ] .

    
por 26.10.2015 / 09:57
4

Você pode fazer isso:

  • extrair os valores de ano / mês / dia em uma variável de shell,
  • crie um arquivo temporário
  • use o comando touch (adicionando 0s por hora / minuto / segundo) a definir a data de modificação para o arquivo temporário

Como sua pergunta é sobre bash , provavelmente você está usando o Linux. O programa test usado no Linux (parte de coreutils ) possui extensões para comparação de timestamp ( -nt e -ot ) não encontradas em POSIX test .

POSIX comenta sobre isso no raciocínio para test :

Some additional primaries newly invented or from the KornShell appeared in an early proposal as part of the conditional command ([[]]): s1 > s2, s1 < s2, str = pattern, str != pattern, f1 -nt f2, f1 -ot f2, and f1 -ef f2. They were not carried forward into the test utility when the conditional command was removed from the shell because they have not been included in the test utility built into historical implementations of the sh utility.

Usando essa extensão, você poderia então

  • crie outro arquivo temporário com a data que você deseja comparar com
  • use o operador -nt em test para fazer a comparação solicitada.

Aqui está um exemplo. Um esclarecimento por OP mencionou a plataforma, portanto, pode-se usar stat como uma alternativa aos arquivos temporários (compare OSX e 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
    
por 26.10.2015 / 09:28
1

Outra abordagem zsh :

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 ]]'@)

Informaria os arquivos com algo que se parece com um registro de data e hora em seu nome, mas que não corresponde ao horário da última modificação.

zsh tem uma infinidade de operadores para manipular globs e variáveis. É muito útil fazer qualquer trabalho rapidamente (e geralmente de forma confiável), mas é muito difícil dar uma olhada em todos eles e geralmente produz o que normalmente chamamos de código write-only (eufemismo para código ilegível, embora também implique que você não precisa lê-lo ao escrevê-lo para um único uso no prompt de comando)

Uma rápida explicação:

  • **/pattern(qualifier) : glob recursiva com qualificador glob.
  • [0-9](#c8) corresponde a 8 dígitos. Esse é o equivalente a sprig estendido de ksh {8}([0-9]) .
  • D : inclua arquivos ocultos
  • e@...@ : o qualificador de glob eval para executar algum texto para qualificar ainda mais os arquivos. Caminho do arquivo passado em $REPLY
  • zstat... recupera o mtime formatado como YYYYMMDD na matriz $m .
  • ${REPLY:t} : expande para a cauda t (o nome da base) do arquivo.
  • %código%. Extraia a parte correspondente a padrão de algo . Aquelas ${(SM)something#pattern} (pesquisa S ) e S (expansão para M porção atada) são chamadas flags de expansão de parâmetro .
por 29.10.2015 / 12:46