Come trovare ricorsivamente l'ultimo file modificato in una directory?


Risposte:


357
find . -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" "

Per un albero enorme, potrebbe essere difficile sortmantenere tutto in memoria.

%T@ti dà il tempo di modifica come un timestamp unix, sort -nordina numericamente, tail -1prende l'ultima riga (timestamp più alto), cut -f2 -d" "taglia il primo campo (timestamp) dall'output.

Modifica: Proprio come -printfprobabilmente è solo GNU, anche l'uso ajreals stat -cè. Sebbene sia possibile fare lo stesso su BSD, le opzioni per la formattazione sono diverse (-f "%m %N" sembrerebbe)

E mi mancava la parte del plurale; se volete più allora l' ultimo file, basta urtare l'argomento coda.


7
Se l'ordine conta, puoi cambiare uso sort -rn | head -3invece di sort -n | tail -3. Una versione fornisce i file dal più vecchio al più recente, mentre l'altra passa dal più recente al più vecchio.
Don Faulkner,

3
Avevo una directory enorme (circa diecimila piccoli file) ed ero preoccupato per le prestazioni, ma ... questo comando viene eseguito in meno di un secondo! Grazie mille !!! :-)
lucaferrario il

2
"Per un albero enorme, potrebbe essere difficile per l'ordinamento mantenere tutto in memoria." sortcreerà file temporanei (in /tmp) in base alle necessità, quindi non credo sia una preoccupazione.
Vladimir Panteleev,

1
modificandolo in: -printf '%T@ %Tb %Td %TY %p\n'ti darà un timbro data (se necessario) (simile a ls)
bshea

1
Trovo il seguente più breve e con un output più interpretabile:find . -type f -printf '%TF %TT %p\n' | sort | tail -1
snth

129

Seguendo la risposta di @ plundra , ecco la versione di BSD e OS X:

find . -type f -print0 | xargs -0 stat -f "%m %N" |
sort -rn | head -1 | cut -f2- -d" "

1
BSD / OS X findsupporta +invece di \;? Perché fa la stessa cosa (passando più file come parametri), senza -print0 | xargs -0pipe.
DevSolar,

Cosa fare se si desidera modificare gli ultimi 5 o n numeri di file in ordine decrescente?
Khunshan,

@khunshan cambia head -1inhead -5
Emerson Farrugia il

20

Invece di ordinare i risultati e conservare solo gli ultimi modificati, è possibile utilizzare awk per stampare solo quello con il tempo di modifica maggiore (in tempo unix):

find . -type f -printf "%T@\0%p\0" | awk '
    {
        if ($0>max) {
            max=$0; 
            getline mostrecent
        } else 
            getline
    } 
    END{print mostrecent}' RS='\0'

Questo dovrebbe essere un modo più veloce per risolvere il tuo problema se il numero di file è abbastanza grande.

Ho usato il carattere NUL (cioè '\ 0') perché, in teoria, un nome file può contenere qualsiasi carattere (inclusi spazio e newline) tranne quello.

Se non hai tali nomi di file patologici nel tuo sistema, puoi usare anche il carattere di nuova riga:

find . -type f -printf "%T@\n%p\n" | awk '
    {
        if ($0>max) {
            max=$0; 
            getline mostrecent
        } else 
            getline
    } 
    END{print mostrecent}' RS='\n'

Inoltre, funziona anche nel mawk.


Questo potrebbe essere facilmente adattato per mantenere i tre più recenti.
In pausa fino a nuovo avviso.

1
Questo non funziona con mawkl'alternativa standard Debian.
Jan

No, ma in quel caso puoi usare il carattere di nuova riga se non ti dà fastidio;)
marco,

10

Ho avuto il problema di trovare l'ultimo file modificato in Solaris 10. Non findesiste l' printfopzione e statnon è disponibile. Ho scoperto la seguente soluzione che funziona bene per me:

find . -type f | sed 's/.*/"&"/' | xargs ls -E | awk '{ print $6," ",$7 }' | sort | tail -1

Per mostrare anche il nome file, utilizzare

find . -type f | sed 's/.*/"&"/' | xargs ls -E | awk '{ print $6," ",$7," ",$9 }' | sort | tail -1

Spiegazione

  • find . -type f trova ed elenca tutti i file
  • sed 's/.*/"&"/' racchiude il percorso tra virgolette per gestire gli spazi bianchi
  • xargs ls -Einvia il percorso citato a ls, l' -Eopzione si assicura che un timestamp completo (formato anno-mese-giorno ora-minuto-secondi-nanosecondi venga restituito )
  • awk '{ print $6," ",$7 }' estrae solo data e ora
  • awk '{ print $6," ",$7," ",$9 }' estrae data, ora e nome file
  • sort restituisce i file ordinati per data
  • tail -1 restituisce solo l'ultimo file modificato

9

Questo sembra funzionare bene, anche con le sottodirectory:

find . -type f | xargs ls -ltr | tail -n 1

In caso di troppi file, perfeziona la ricerca.


1
L' -lopzione lssembra non necessaria. Proprio -trsembra sufficiente.
Acumenus,

6
Questo sembra ordinare per directory, quindi non mostrerà necessariamente l'ultimo file
Fabian Schmengler

1
Nel caso ci siano spazi nei percorsi dei file meglio fare:find . -type f -print0 | xargs -0 ls -ltr | tail -n 1
Manutenzione periodica

Questo non trova gli ultimi file per me.
K.-Michael Aye,

1
Pensa che questo si rompa se ci sono spazi nei nomi dei file
waferthin

7

Mostra l'ultimo file con data / ora leggibile dall'uomo:

find . -type f -printf '%TY-%Tm-%Td %TH:%TM: %Tz %p\n'| sort -n | tail -n1

Il risultato è simile al seguente:

2015-10-06 11:30: +0200 ./foo/bar.txt

Per mostrare più file, sostituiscilo -n1con un numero più alto


5

Uso sempre qualcosa di simile, così come l'elenco top-k degli ultimi file modificati. Per alberi di directory di grandi dimensioni, può essere molto più veloce per evitare l'ordinamento . Nel caso del solo file 1 modificato più di recente:

find . -type f -printf '%T@ %p\n' | perl -ne '@a=split(/\s+/, $_, 2); ($t,$f)=@a if $a[0]>$t; print $f if eof()'

Su una directory contenente 1,7 milioni di file, ottengo il più recente in 3.4s, una velocità di 7.5x rispetto alla soluzione di 25.5s usando sort.


Molto bello: ho appena scambiato l'ultima stampa con: system ("ls -l $ f") if eof () per vedere anche la data in modo carino.
Martin T.

@MartinT. : fantastico, e prego. È strano per me che le persone abbiano questo istinto di ordinare le cose (O (n log n)) quando è disponibile un metodo O (n). Questa sembra essere l'unica risposta che evita l'ordinamento. A proposito, l'obiettivo del comando che ho suggerito è solo quello di trovare il percorso dell'ultimo file. Potresti alias il comando nella tua shell (es. Come lastfile) e quindi puoi fare quello che vuoi con il risultato, come ls -l $(lastfile .), o open $(lastfile .)(su un Mac), ecc.
Pierre D,

Oh, sono corretto: vedo un'altra risposta sotto (@marco). +1.
Pierre D,

4

Questo dà un elenco ordinato:

find . -type f -ls 2>/dev/null | sort -M -k8,10 | head -n5

Invertire l'ordine inserendo '-r' nel comando di ordinamento. Se vuoi solo nomi di file, inserisci "awk '{print $ 11}' |" prima di "| testa'


3

Su Ubuntu 13, ciò che segue lo fa, forse un po 'più veloce, poiché inverte l'ordinamento e usa' testa 'invece di' coda ', riducendo il lavoro. Per mostrare gli 11 file più recenti in un albero:

trova . -type f -printf '% T @% p \ n' | ordina -n -r | testa -11 | cut -f2- -d "" | sed -e 's, ^. / ,,' | xargs ls -U -l

Questo fornisce un elenco completo di ls senza riordinamento e omette il fastidioso './' che 'find' inserisce ogni nome di file.

Oppure, come funzione bash:

treecent () {
  local numl
  if [[ 0 -eq $# ]] ; then
    numl=11   # Or whatever default you want.
  else
    numl=$1
  fi
  find . -type f -printf '%T@ %p\n' | sort -n -r | head -${numl} |  cut -f2- -d" " | sed -e 's,^\./,,' | xargs ls -U -l
}

Tuttavia, gran parte del lavoro è stato svolto dalla soluzione originale di Plundra. Grazie plundra.


3

Ho affrontato lo stesso problema. Devo trovare ricorsivamente il file più recente. trovare ha impiegato circa 50 minuti per trovare.

Ecco un piccolo script per farlo più velocemente:

#!/bin/sh

CURRENT_DIR='.'

zob () {
    FILE=$(ls -Art1 ${CURRENT_DIR} | tail -n 1)
    if [ ! -f ${FILE} ]; then
        CURRENT_DIR="${CURRENT_DIR}/${FILE}"
        zob
    fi
    echo $FILE
    exit
}
zob

È una funzione ricorsiva che ottiene l'elemento modificato più recente di una directory. Se questo elemento è una directory, la funzione viene chiamata ricorsivamente e cerca in questa directory, ecc.


3

Trovo il seguente output più breve e con più interpretabile:

find . -type f -printf '%TF %TT %p\n' | sort | tail -1

Data la lunghezza fissa dei tempi di trasmissione standardizzati del formato ISO, l'ordinamento lessicografico va bene e non abbiamo bisogno -ndell'opzione sull'ordinamento .

Se si desidera rimuovere nuovamente i timestamp, è possibile utilizzare:

find . -type f -printf '%TFT%TT %p\n' | sort | tail -1 | cut -f2- -d' '

2

Se l'esecuzione statsu ogni file singolarmente è un rallentamento, puoi usare xargsper accelerare un po 'le cose:

find . -type f -print0 | xargs -0 stat -f "%m %N" | sort -n | tail -1 | cut -f2- -d" " 

2

Ciò modifica in modo ricorsivo il tempo di modifica di tutte le directory nella directory corrente nel file più recente in ciascuna directory:

for dir in */; do find $dir -type f -printf '%T@ "%p"\n' | sort -n | tail -1 | cut -f2- -d" " | xargs -I {} touch -r {} $dir; done

1
Si rompe male se qualche dir contiene spazi - è necessario impostare IFS e usare le virgolette: IFS = $ '\ n'; per dir in $ (find ./ -type d); fare eco "$ dir"; trova "$ dir" -type f -printf '% T @ "% p" \ n' | ordina -n | coda -1 | cut -f2- -d "" | xargs -I {} touch -r {} "$ dir"; fatto;
Andy Lee Robinson,

2

Questo semplice cli funzionerà anche:

ls -1t | head -1

È possibile modificare -1 per il numero di file che si desidera elencare


10
No, non lo sarà, poiché non è ricorsivo.
Arataj,

1

Ho trovato utile il comando sopra, ma per il mio caso avevo bisogno di vedere anche la data e l'ora del file e ho avuto un problema con diversi file con spazi nei nomi. Ecco la mia soluzione di lavoro.

find . -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" " | sed 's/.*/"&"/' | xargs ls -l

1

Il seguente comando ha funzionato su Solaris:

find . -name "*zip" -type f | xargs ls -ltr | tail -1 

1

Ignorare i file nascosti - con timestamp piacevole e veloce

$ find . -type f -not -path '*/\.*' -printf '%TY.%Tm.%Td %THh%TM %Ta %p\n' |sort -nr |head -n 10

Risultato

Gestisce bene gli spazi nei nomi dei file - non che questi debbano essere usati!

2017.01.25 18h23 Wed ./indenting/Shifting blocks visually.mht
2016.12.11 12h33 Sun ./tabs/Converting tabs to spaces.mht
2016.12.02 01h46 Fri ./advocacy/2016.Vim or Emacs - Which text editor do you prefer?.mht
2016.11.09 17h05 Wed ./Word count - Vim Tips Wiki.mht

Di Più

Più a find bizzeffe seguendo il link.


1

Per cercare i file in / target_directory e tutte le sue sottodirectory, che sono state modificate negli ultimi 60 minuti:

$ find /target_directory -type f -mmin -60

Per trovare i file modificati più di recente, ordinati in ordine inverso rispetto al tempo di aggiornamento (ovvero, i file aggiornati più di recente per primi):

$ find /etc -type f -printf '%TY-%Tm-%Td %TT %p\n' | sort -r

0

Preferisco questo, è più corto:

find . -type f -print0|xargs -0 ls -drt|tail -n 1

0

Ho scritto un pacchetto pypi / github per questa domanda perché avevo bisogno anche di una soluzione.

https://github.com/bucknerns/logtail

Installare:

pip install logtail

Uso: tails ha cambiato i file

logtail <log dir> [<glob match: default=*.log>]

Usage2: Apre l'ultimo file modificato nell'editor

editlatest <log dir> [<glob match: default=*.log>]
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.