Trova l'ultimo file per data modificata


39

Se voglio trovare l'ultimo file (mtime) in una (grande) directory contenente sottodirectory, come lo farei?

Molti post che ho trovato suggeriscono alcune variazioni ls -lt | head(in modo divertente, molti suggeriscono ls -ltr | tailche è lo stesso ma meno efficiente) che va bene a meno che tu non abbia delle sottodirectory (lo faccio).

Poi di nuovo, potresti

find . -type f -exec ls -lt \{\} \+ | head

che farà sicuramente il trucco per tutti i file che possono essere specificati da un comando, cioè se hai una grande directory, -exec...\+emetterà comandi separati; pertanto ogni gruppo verrà ordinato da lssolo, ma non sull'insieme totale; la testa raccoglierà quindi l'ultima voce del primo lotto.

Qualche risposta?


a proposito, non hai bisogno di nessuna di quelle barre rovesciate.
enzotib,

@enzotib: lo fai ( \ + ), altrimenti ottienifind: missing argument to '-exec'
organizza il

@arrange: non ho questo errore, in quanto +non ha alcun significato bash, quindi non c'è bisogno di evitarlo.
enzotib,

@enzotib: hai ragione, errore mio, scusa
organizza il

Risposte:


46

Non è necessario ricorrere a comandi esterni (as ls) perché findpuò fare tutto ciò che serve attraverso l' -printfazione:

find /path -printf '%T+ %p\n' | sort -r | head

1
Sì, mi è venuto in mente find . -type f -exec stat --format=%y \{\} \+ | sort -r | head -n1ma la tua soluzione è molto più pulita!
Ricco

3
Aggiungi | cut -d ' ' -f2per ottenere solo il nome file
qwr

Puoi anche selezionare l'output di headper includere un certo numero di righe. Avevo solo bisogno della prima riga, quindi ho usatohead -n 1
Timmah,

8

Ho avuto un problema simile oggi, ma l'ho attaccato senza find. Avevo bisogno di qualcosa di breve da poter ricorrere sshper restituire l'ultimo file modificato nella mia directory home. Questo è approssimativamente quello che mi è venuto in mente:

ls -tp | grep -v /$ | head -1

L' -popzione per lsaggiungere una barra finale alle directory, grep -vrimuove le righe che terminano in una barra (ovvero tutte le directory) e head -1limita l'output a un singolo file.

Questo è molto meno dettagliato dell'uso findse tutto ciò che vuoi restituire è il nome del file.


Questo non gestisce le sottodirectory.
Clément il

4

Questo è sul mio sistema più veloce di printf, anche se non capisco perché

find /path -type f -exec stat -c "%y %n" {} + | sort -r | head

Confermo, è più veloce.
enzotib,

Un altro punto, ... | sort -r | head -n1 | cut -d " " -f 4-se si desidera ottenere solo il nome file.
林果 皞

Ho appena trovato sort -rsbagliato se esiste un nome file su più righe.
皞 皞

2

EDIT: suppongo che questo post non sia "non particolarmente utile" come pensavo. Questa è una soluzione davvero veloce che tiene traccia del file modificato più di recente (invece di ordinare l'intero elenco di file):

find . -type f -printf '%T@ %p\n' | awk 'BEGIN { mostrecenttime = 0; mostrecentline = "nothing"; } { if ($1 > mostrecenttime) { mostrecenttime = $1; mostrecentline = $0; } } END { print mostrecentline; }' | cut -f2- -d ' '

Distribuito su più righe per maggiore chiarezza, appare come segue:

find . -type f -printf '%T@ %p\n' | awk '
    BEGIN { mostrecenttime = 0; mostrecentline = "nothing"; }
    {
        if ($1 > mostrecenttime)
            { mostrecenttime = $1; mostrecentline = $0; }
    }
    END { print mostrecentline; }' | cut -f2- -d ' '

Fine di EDIT


Non è un post particolarmente utile ma dato che "organizzare" stava discutendo della velocità, ho pensato di condividerlo.

Le soluzioni di arrangiamento ed enzotib comportano elencare tutti i file all'interno della directory con i loro mtime e quindi ordinarli. Come sai l'ordinamento non è necessario per trovare il massimo. Trovare il massimo può essere fatto in tempo lineare, ma l'ordinamento richiede n log (n) tempo [So che la differenza non è molto, ma comunque;)]. Non riesco a pensare a un modo pulito per implementarlo. [EDIT: un'implementazione pulita (anche se sporca) e veloce fornita sopra.]

Prossima cosa migliore - Per trovare il file modificato più di recente in una directory, trova ricorsivamente il file modificato più di recente in ogni sottodirectory di livello 1. Lascia che questo file rappresenti la sottodirectory. Ora ordina i file di livello 1 insieme ai rappresentanti delle sottodirectory di livello 1. Se il numero di file e sottodirectory di livello 1 di ciascuna directory è quasi una costante, questo processo dovrebbe ridimensionarsi linearmente con il numero totale di file.

Questo è quello che mi è venuto in mente per implementare questo:

findrecent() { { find "$1" -maxdepth 1 -type f -exec stat -c "%y %n" {} + | sort -r | head -1 && find "$1" -mindepth 1 -maxdepth 1 -type d -exec findrecent {} \;; } | sort -r | head -1; }
findrecent .

Ho eseguito questo e ho avuto un sacco di find: findrecent: No such file or directoryerrori. Motivo: -exec di find viene eseguito in una shell diversa. Ho provato a definire findrecent in .bashrc, .xsessionrc ma questi non mi hanno aiutato [apprezzerei l'aiuto qui]. Alla fine ho fatto ricorso al mettere

#!/bin/bash
{ find "$1" -maxdepth 1 -type f -exec stat -c "%y %n" {} + | sort -r | head -1 && find "$1" -mindepth 1 -maxdepth 1 -type d -exec findrecent {} \;; } | sort -r | head -1;

in uno script chiamato findrecentnel mio PERCORSO e quindi in esecuzione.

Ho eseguito questo, ho continuato ad aspettare e ad aspettare senza uscita. Solo per essere sicuro di non avere a che fare con loop infiniti in cui ho modificato il file

#!/bin/bash
echo "$1" >&2
{ find "$1" -maxdepth 1 -type f -exec stat -c "%y %n" {} + | sort -r | head -1 && find "$1" -mindepth 1 -maxdepth 1 -type d -exec findrecent {} \;; } | sort -r | head -1;

e riprovato. Ha funzionato - ma ci sono voluti 1 minuto e 35 secondi sulla mia cartella di casa - le soluzioni di organ ed enzotib hanno richiesto rispettivamente 1,69, 1,95 secondi!

Questo per quanto riguarda la superiorità di O (n) su O (n log (n))! Dannazione, la tua funzione è chiamata in testa! [O piuttosto overhead della chiamata di script]

Ma questo script si adatta meglio delle soluzioni precedenti e scommetto che funzionerà più velocemente di loro sul banco di memoria di Google; D


2

Utilizzare perlin congiunzione con find:

 find my_directory -type f -printf '%T@\t%p\n' | perl -ane '@m=@F if ($F[0]>$m[0]); END{print $m[1];}'

Ottieni il nome del file con la massima epoca == ultimo file modificato.


1

Non è altrettanto alla moda, ma è anche possibile farlo con Midnight Commander : cerca *, riordina il risultato, ordina per tempo di modifica in ordine inverso.

Ovviamente, è un po 'più lento di find- la mia directory home, contenente 922000 file, è stata ordinata mcin quasi 14 minuti mentre ho findtrascorso meno di 5 - ma ci sono alcuni vantaggi:

  • Probabilmente impiegherei più tempo della differenza di 9 minuti a inventare una corretta chiamata di ricerca :)

  • meno possibilità di errore (dimenticato di specificare -r per l'ordinamento ecc. - ricomincia)

  • è possibile giocare con il set di risultati modificando l'ordinamento ecc. - senza eseguire nuovamente la query dei file.

  • possibile eseguire operazioni sui file solo su alcuni file del set di risultati - ovvero ordinare per dimensione, eliminare alcuni file di grandi dimensioni che non sono necessari

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.