Como eu altero recursivamente os registros de data e hora da pasta para o arquivo mais novo?

14

Eu queria saber se alguém sabe como alterar a data e a hora das pastas recursivamente com base no último registro de data e hora encontrado nos arquivos dessa pasta.

Então, por exemplo:

jon@UbuntuPanther:/media/media/MP3s/Foo Fighters/(1997-05-20) The Colour and The Shape$ ls -alF
total 55220
drwxr-xr-x  2 jon jon    4096 2010-08-30 12:34 ./
drwxr-xr-x 11 jon jon    4096 2010-08-30 12:34 ../
-rw-r--r--  1 jon jon 1694044 2010-04-18 00:51 Foo Fighters - Doll.mp3
-rw-r--r--  1 jon jon 3151170 2010-04-18 00:51 Foo Fighters - Enough Space.mp3
-rw-r--r--  1 jon jon 5004289 2010-04-18 00:52 Foo Fighters - Everlong.mp3
-rw-r--r--  1 jon jon 5803125 2010-04-18 00:51 Foo Fighters - February Stars.mp3
-rw-r--r--  1 jon jon 4994903 2010-04-18 00:51 Foo Fighters - Hey, Johnny Park!.mp3
-rw-r--r--  1 jon jon 4649556 2010-04-18 00:52 Foo Fighters - Monkey Wrench.mp3
-rw-r--r--  1 jon jon 5216923 2010-04-18 00:51 Foo Fighters - My Hero.mp3
-rw-r--r--  1 jon jon 4294291 2010-04-18 00:52 Foo Fighters - My Poor Brain.mp3
-rw-r--r--  1 jon jon 6778011 2010-04-18 00:52 Foo Fighters - New Way Home.mp3
-rw-r--r--  1 jon jon 2956287 2010-04-18 00:51 Foo Fighters - See You.mp3
-rw-r--r--  1 jon jon 2730072 2010-04-18 00:51 Foo Fighters - Up in Arms.mp3
-rw-r--r--  1 jon jon 6086821 2010-04-18 00:51 Foo Fighters - Walking After You.mp3
-rw-r--r--  1 jon jon 3033660 2010-04-18 00:52 Foo Fighters - Wind Up.mp3

A pasta "(1997-05-20) A cor e a forma" teria seu registro de data e hora definido como 2010-04-18 00:52.

    
por MonkeyWrench32 02.09.2010 / 23:16

7 respostas

20

Você pode usar touch -r para usar o registro de data e hora de outro arquivo em vez do horário atual (ou touch --reference=FILE )

Aqui estão duas soluções. Em cada solução, o primeiro comando altera a hora da modificação do diretório para a do arquivo mais novo imediatamente abaixo dele, e o segundo comando examina a árvore do diretório inteiro de forma recursiva. Mude para o diretório ( cd '.../(1997-05-20) The Colour and The Shape' ) antes de executar qualquer um dos comandos.

Em zsh (remova o D para ignorar arquivos de ponto):

touch -r *(Dom[1]) .
touch -r **/*(Dom[1]) .

No Linux (ou mais geralmente com o GNU find):

touch -r "$(find -mindepth 1 -maxdepth 1 -printf '%T+=%p\n' |
            sort |tail -n 1 | cut -d= -f2-)" .
touch -r "$(find -mindepth 1 -printf '%T+=%p\n' |
            sort |tail -n 1 | cut -d= -f2-)" .

No entanto, observe que esses não assumem nenhum caractere de nova linha em nomes de arquivos.

    
por 02.09.2010 / 23:39
3

Isso não é "recursivamente", apenas altera todos os carimbos de data e hora em uma pasta. Se é isso que você quer dizer, há dois passos.

stat -c '%Y' filename exibirá o registro de data e hora de filename e stat -c '%Y %n' * exibirá o registro de data e hora e o nome de arquivo de todos os arquivos na pasta, assim ele encontrará o nome do arquivo modificado mais recentemente pasta:

mostrecent="'stat -c '%Y %n' * | sort -n | tail -n1 | cut -d ' ' -f '2-''"

Pensando bem, há uma maneira way mais fácil de obter o timestamp mais alto na pasta:

mostrecent="'ls -t | head -n1'"

Em seguida, você deseja alterar todos os arquivos na pasta para que tenham o mesmo registro de data e hora desse arquivo. touch -r foo bar mudará bar para ter o mesmo registro de data e hora modificado de foo , portanto, isso alterará todos os arquivos da pasta para que tenham o mesmo registro de data e hora modificado que o arquivo modificado mais recentemente:

touch -r "$mostrecent" *

Então, o one-liner é:

touch -r "'ls -t | head -n1'" *
    
por 02.09.2010 / 23:26
2

Eu juntei o trabalho e agora:

Este seria um script que altera todos os diretórios dentro de /tmp/test/ para o registro de data e hora do arquivo mais novo dentro de cada diretório:

#!/bin/bash
if [ -z "$1" ] ; then
  echo 'ERROR: Parameter missing. specify the folder!'
  exit
fi
#MODE=tail # change to newest file
MODE=head # change to oldest file
for d in "$1"/*/; do
  echo "running on $d"
  find "$d" -type d -execdir \
    echo touch --reference="$(find "$d" -mindepth 1 -maxdepth 1 -printf '%T+=%p\n' \
                              | sort | "$MODE" -n 1 | cut -d= -f2-)" "$d" \;
    # remove echo to really run it
done

você pode adicionar alguns arquivos de teste em / tmp assim:

mkdir /tmp/test
cd /tmp/test
mkdir d1
mkdir d2
touch d1/text1.txt
sleep 1
touch d1/movie1.mov
touch d2/movie2.mov
sleep 1
touch d2/text2.txt
touch notthis.file
    
por 14.08.2013 / 18:06
1

é só usar

find . -exec touch {} \;
    
por 18.08.2016 / 10:29
0

Eu uso esse script para definir recursivamente os carimbos de data / hora da pasta para o conteúdo mais recente. (É muito parecido com a resposta de Gilles):

#! /bin/bash

# Change mtime of directories to that of latest file (or dir) under it, recursively
# Empty leaf directories, or dirs with only symlinks get the $default_timestamp

default_timestamp='1980-01-01 00:00:00'

dir="$1"

[ -d "$dir" ] || { echo "Usage: $0 directory" >&2; exit 1; }

find "$dir" -depth -type d | while read d; do
    latest=$(find "$d" -mindepth 1 -maxdepth 1 \( -type f -o -type d \) -printf '%T@ %p\n' | sort -n | tail -1 | cut -d' ' -f2-)
    if [ -n "$latest" ]; then
        touch -c -m -r "$latest" "$d" \
            || echo "ERROR setting mtime of '$d' using ref='$f'" >&2
    else
        touch -c -m -d "$default_timestamp" "$d" \
            || echo "ERROR setting mtime of '$d' to default '$default_timestamp'" >&2
    fi
done
    
por 18.03.2017 / 18:43
0

Eu peguei o comando @Gilles zsh e o aprimorei para trabalhar em subpastas, mas parece que o zsh é terrivelmente ineficiente para a parte ** / * (FDod).

# Don't do this
for d in **/*(FDod); do touch -r "$d"/*(Dom[1]) "$d"; done

As citações permitem que entradas de diretório contendo espaços e tabulações funcionem corretamente. O FD faz com que ele encontre diretórios não vazios, incluindo aqueles que começam com., O od faz com que ele procure na maneira profundidade primeiro , para que os carimbos de data e hora da pasta pai sejam atualizados adequadamente.

Durante o teste, notei que o desempenho e a memória ocupada por ** / * (FDod) eram insanos (acima de 1,4 GB para apenas 650k pastas) e liam tudo antes de começar a tocar nas pastas. Depois de substituí-lo por find / read, ele ficou muito mais rápido, não queimou a memória e começou quase imediatamente.

#! /usr/bin/env zsh
# Do this instead
find "$@" -depth -type d ! -empty -print0 |while IFS= read -r -d ''; do
    touch -r "$REPLY"/*(Dom[1]) "$REPLY"
done

Se você não estiver executando em um script, substitua "$ @" pelas pastas das quais deseja executá-lo.

    
por 08.11.2018 / 09:19
-1

Eu realmente não gostei da obscuridade dos comandos do shell e rapidamente fiz isso em python.

Ele recursivamente define todos os tempos de diretório para o mais novo arquivo / diretório não excluído dentro.

import os
import sys

EXCLUDE_FILES = ['.DS_Store']
EXCLUDE_DIRS = ['.git', '.hg']

def inheritMTime(path):
    for root, dirs, files in os.walk(path, topdown=False, followlinks=False):
        currentMaxMtime = None
        for subpath in files:
            if subpath in EXCLUDE_FILES:
                print "ignore file", os.path.join(root, subpath)
                continue
            currentMaxMtime = max(currentMaxMtime, os.lstat(os.path.join(root, subpath)).st_mtime)
        for subpath in dirs:
            if subpath in EXCLUDE_DIRS:
                print "ignore dir", os.path.join(root, subpath)
                continue
            currentMaxMtime = max(currentMaxMtime, os.lstat(os.path.join(root, subpath)).st_mtime)
        if currentMaxMtime is not None:
            os.utime(root, (currentMaxMtime, currentMaxMtime))

if __name__ == "__main__":
    for dir in os.listdir(sys.argv[1]):
        if os.path.isdir(dir):
            current = os.path.join(sys.argv[1], dir)
            inheritMTime(current)
    
por 31.01.2016 / 11:33