Come trovare ricorsivamente e elencare gli ultimi file modificati in una directory con sottodirectory e orari?

Ho diverse directory con diverse sottodirectory e file in esse. Ho bisogno di creare un elenco di tutte queste directory costruite in modo tale che ogni directory di primo livello sia elencata accanto alla data e all’ora dell’ultimo file creato / modificato al suo interno.

Per chiarire, se tocchi un file o modifichi il contenuto di alcuni livelli di sottodirectory, tale timestamp dovrebbe essere visualizzato accanto al nome della directory di primo livello. Dire che ho una directory strutturata in questo modo:

./alfa/beta/gamma/example.txt 

e modifico il contenuto del file example.txt , ho bisogno di quel tempo visualizzato accanto alla directory alfa primo livello in forma leggibile dall’uomo, non in epoca. Ho provato alcune cose usando find, xargs , sort e simili, ma non posso aggirare il problema che il timestamp del file system di ‘alfa’ non cambia quando creo / modifichi i file di alcuni livelli.

Prova questo:

 #!/bin/bash find $1 -type f -exec stat --format '%Y :%y %n' "{}" \; | sort -nr | cut -d: -f2- | head 

Eseguilo con il percorso della directory in cui dovrebbe iniziare la scansione in modo ricorsivo (supporta nomi di file con spazi).

Se ci sono molti file potrebbe volerci un po ‘prima che restituisca qualcosa. Le prestazioni possono essere migliorate se usiamo invece xargs :

 #!/bin/bash find $1 -type f -print0 | xargs -0 stat --format '%Y :%y %n' | sort -nr | cut -d: -f2- | head 

che è un po ‘più veloce.

Per trovare tutti i file che lo stato del file è stato modificato l’ultima volta N minuti fa:

find -cmin -N

per esempio:

find -cmin -5

Ho accorciato la splendida risposta di halo a questo one-liner

 stat --printf="%y %n\n" $(ls -tr $(find * -type f)) 

Aggiornato : se ci sono spazi nei nomi di file, è ansible utilizzare questa modifica

 OFS="$IFS";IFS=$'\n';stat --printf="%y %n\n" $(ls -tr $(find . -type f));IFS="$OFS"; 

GNU Find (vedi man find ) ha un parametro -printf per la visualizzazione dei file EPOC mtime e il relativo nome del percorso.

 redhat> find . -type f -printf '%[email protected] %P\n' | sort -n | awk '{print $2}' 

Prova questo

 #!/bin/bash stat --format %y $(ls -t $(find alfa/ -type f) | head -n 1) 

Usa find per raccogliere tutti i file dalla directory, per elencarli ordinati per data di modifica, per selezionare il primo file e infine per mostrare l’ora in un formato piacevole.

Al momento non è sicuro per i file con spazi bianchi o altri caratteri speciali nei loro nomi. Scrivi un elogio se non soddisfa ancora le tue esigenze.

Questo comando funziona su Mac OS X:

find "$1" -type f -print0 | xargs -0 stat --format '%Y :%y %n' | sort -nr | cut -d: -f2- | head

Su Linux, come richiesto dal poster originale, usa stat posto di gstat .

Questa risposta è, naturalmente, la soluzione eccezionale di user37078 , promossa dal commento alla risposta completa. Ho mescolato le informazioni di CharlesB per usare gstat su Mac OS X. A proposito, ho ricevuto coreutils da MacPorts piuttosto che da homebrew .

Ed ecco come ho impacchettato questo in un semplice comando ~/bin/ls-recent.sh per il riutilizzo:

 #!/bin/bash # ls-recent: list files in a dir tree, most recently modified first # # Usage: ls-recent path [-10 | more] # # Where "path" is a path to target directory, "-10" is any arg to pass # to "head" to limit the number of entries, and "more" is a special arg # in place of "-10" which calls the pager "more" instead of "head". if [ "more" = "$2" ]; then H=more; N='' else H=head; N=$2 fi find "$1" -type f -print0 |xargs -0 gstat --format '%Y :%y %n' \ |sort -nr |cut -d: -f2- |$H $N 

Sia le soluzioni perl che Python in questo post mi hanno aiutato a risolvere questo problema su Mac OS X: https://unix.stackexchange.com/questions/9247/how-to-list-files-sorted-by-modification-date-recursively -no-stat-command-avail .

Citando dal post:

Perl:

 find . -type f -print | perl -l -ne ' $_{$_} = -M; # store file age (mtime - now) END { $,="\n"; print sort {$_{$b} <=> $_{$a}} keys %_; # print by decreasing age }' 

Pitone:

 find . -type f -print | python -c 'import os, sys; times = {} for f in sys.stdin.readlines(): f = f[0:-1]; times[f] = os.stat(f).st_mtime for f in sorted(times.iterkeys(), key=lambda f:times[f]): print f' 

Lo sto mostrando per gli ultimi tempi di accesso, puoi facilmente modificarlo per fare l’ultima volta.

Ci sono due modi per farlo:


1) Se vuoi evitare l’ordinamento globale che può essere costoso se hai decine di milioni di file, allora puoi fare: (posizionarsi nella radice della directory in cui si desidera avviare la ricerca)

 linux> touch -d @0 /tmp/a; linux> find . -type f -exec tcsh -f -c test `stat --printf="%X" {}` -gt `stat --printf="%X" /tmp/a` ; -exec tcsh -f -c touch -a -r {} /tmp/a ; -print 

Il metodo precedente stampa i nomi dei file con un tempo di accesso progressivamente più recente e l’ultimo file che stampa è il file con l’ora di accesso più recente. Ovviamente puoi ottenere il tempo di accesso più recente utilizzando una “coda -1”.


2) È ansible trovare in modo ricorsivo il nome, il tempo di accesso di tutti i file nella sottodirectory e quindi ordinare in base al tempo di accesso e alla coda la voce più grande:

 linux> \find . -type f -exec stat --printf="%X %n\n" {} \; | \sort -n | tail -1 

E il gioco è fatto…

Ho questo alias nel mio profilo che uso abbastanza spesso

 $ alias | grep xlogs xlogs='sudo find . \( -name "*.log" -o -name "*.trc" \) -mtime -1 | sudo xargs ls -ltr --color | less -R' 

Così fa quello che stai cercando (con l’eccezione che non attraversa la modifica di data / ora su più livelli): cerca i file più recenti (file * .log e * .trc in questo caso); inoltre trova solo i file modificati nell’ultimo giorno, quindi ordina in base al tempo e l’output delle pipe tramite meno:

 sudo find . \( -name "*.log" -o -name "*.trc" \) -mtime -1 | sudo xargs ls -ltr --color | less -R 

ps. Si noti che non ho root su alcuni server, ma ho sempre sudo, quindi potresti non aver bisogno di quella parte.

Funzione bash rapida:

 # findLatestModifiedFiles(directory, [max=10, [format="%Td %Tb %TY, %TT"]]) function findLatestModifiedFiles() { local d="${1:-.}" local m="${2:-10}" local f="${3:-%Td %Tb %TY, %TT}" find "$d" -type f -printf "%[email protected] :$f %p\n" | sort -nr | cut -d: -f2- | head -n"$m" } 

Trova l’ultimo file modificato in una directory:

 findLatestModifiedFiles "/home/jason/" 1 

Puoi anche specificare il tuo formato data / ora come terzo argomento.

Di seguito viene riportata una stringa del timestamp e il nome del file con il timestamp più recente:

 find $Directory -type f -printf "%TY-%Tm-%Td-%TH-%TM-%TS %p\n" | sed -r 's/([[:digit:]]{2})\.([[:digit:]]{2,})/\1-\2/' | sort --field-separator='-' -nrk1 -nrk2 -nrk3 -nrk4 -nrk5 -nrk6 -nrk7 | head -n 1 

Risultante in un output del modulo:

Ecco una versione che funziona con nomi di file che possono contenere spazi, newline, caratteri glob:

 find . -type f -printf "%[email protected] %p\0" | sort -zk1nr 
  • find ... -printf stampa la modifica del file (valore EPOCH) seguita da uno spazio e \0 nomi di file terminati.
  • sort -zk1nr legge NUL dati terminati e li ordina in ordine numerico

Poiché la domanda è codificata con Linux, gnu utilità gnu siano disponibili.

Puoi pipe sopra con:

 xargs -0 printf "%s\n" 

per stampare i tempi di modifica ei nomi dei file ordinati per ora di modifica (la più recente prima) terminata da una nuova riga.

Ignorando i file nascosti – con un timbro temporale piacevole e veloce

Gestisce bene gli spazi nei nomi dei file – non che dovresti usarli!

 $ find . -type f -not -path '*/\.*' -printf '%TY.%Tm.%Td %THh%TM %Ta %p\n' |sort -nr |head -n 10 2017.01.28 07h00 Sat ./recent 2017.01.21 10h49 Sat ./hgb 2017.01.16 07h44 Mon ./swx 2017.01.10 18h24 Tue ./update-stations 2017.01.09 10h38 Mon ./stations.json 

Più find bizzeffe può essere trovato seguendo il link.

Si può dare il comando printf di trovare una prova

% Tempo ultimo accesso al file Ak nel formato specificato da k, che è una funzione @' or a directive for the C strftime’. I valori possibili per k sono elencati di seguito; alcuni potrebbero non essere disponibili su tutti i sistemi, a causa delle differenze di `strftime ‘tra i sistemi.

Per l’output ls semplice, utilizzare questo. Non c’è un elenco di argomenti, quindi non può essere troppo lungo:

 find . | while read FILE;do ls -d -l "$FILE";done 

E simpatizzato con cut solo per le date, i tempi e il nome:

 find . | while read FILE;do ls -d -l "$FILE";done | cut --complement -d ' ' -f 1-5 

EDIT : appena notato che la risposta superiore corrente ordina per data di modifica. Questo è altrettanto facile con il secondo esempio qui, dato che la data di modifica è la prima su ogni riga – schiaffi un ordinamento verso la fine:

 find . | while read FILE;do ls -d -l "$FILE";done | cut --complement -d ' ' -f 1-5 | sort 

Questo potrebbe essere fatto anche con una funzione ricorsiva in bash

Sia F una funzione che mostra l’ora del file che deve essere lessicalograficamente ordinabile aaaa-mm-gg ecc. (Os-dipendente?)

 F(){ stat --format %y "$1";} # Linux F(){ ls -E "$1"|awk '{print$6" "$7}';} # SunOS: maybe this could be done easier 

R la funzione ricorsiva che scorre attraverso le directory

 R(){ local f;for f in "$1"/*;do [ -d "$f" ]&&R $f||F "$f";done;} 

E infine

 for f in *;do [ -d "$f" ]&&echo `R "$f"|sort|tail -1`" $f";done