2011-06-07 18:23:57 +0000 2011-06-07 18:23:57 +0000
152
152

Unix/Linux trova e ordina per data di modifica

Come posso fare un semplice find che ordinerebbe i risultati in base alle modifiche più recenti?

Ecco l'attuale find che sto usando (sto facendo un escape di shell in PHP, quindi questo è il motivo delle variabili):

find '$dir' -name '$str'\* -print | head -10

Come potrei ordinare la ricerca in base alle modifiche più recenti? (Notate che non voglio che ordini ‘dopo’ la ricerca, ma piuttosto che trovi i risultati in base a ciò che è stato modificato più recentemente).

Risposte (17)

168
168
168
2013-02-05 13:31:01 +0000

Usa questo:

find . -printf "%T@ %Tc %p\n" | sort -n

printf argomenti da man find :

  • %Tk: Tempo di ultima modifica del file nel formato specificato da k.

  • @: secondi dal 1 gennaio 1970, 00:00 GMT, con parte frazionaria.

  • c: data e ora del locale (Sat Nov 04 12:02:33 EST 1989).

  • %p: Nome del file.

85
85
85
2011-06-07 18:39:34 +0000

Il metodo più semplice è usare zsh, grazie ai suoi glob qualifiers .

print -lr -- $dir/**/$str*(om[1,10])

Se avete GNU find, fategli stampare i tempi di modifica dei file e ordinateli in base a quello.

find -type f -printf '%T@ %p```
find -type f -printf '%T@ %p\n' |
sort -k 1nr |
sed 's/^[^]* //' | head -n 10
```' |
sort -zk 1nr |
sed -z 's/^[^]* //' | tr '```
find . -type f -print |
perl -l -ne '
    $_{$_} = -M; # store file age (mtime - now)
    END {
        $,="\n";
        @sorted = sort {$_{$a} <=> $_{$b}} keys %_; # sort by increasing age
        print @sorted[0..9];
    }'
```' '\n' | head -n 10

Se avete GNU find ma non altre utility GNU, usate i newline come separatori invece dei null; perderete il supporto per i nomi di file contenenti newline.

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], reverse=True))[:10]: print f'

Se avete Perl (qui assumo che non ci siano newlines nei nomi dei file):

0x1&

Se avete Python (sempre assumendo che non ci siano newlines nei nomi dei file):

0x1&

C'è probabilmente un modo per fare lo stesso in PHP, ma non lo conosco.

Se vuoi lavorare solo con strumenti POSIX, è un po’ più complicato; vedi Come elencare i file ordinati per data di modifica in modo ricorsivo (nessun comando stat disponibile!) (retatinare i primi 10 è la parte facile).

41
41
41
2011-06-16 18:11:00 +0000

Non avete bisogno di PHP o Python, semplicemente ls :

man ls:
-t sort by modification time
-r, reverse order while sorting (--reverse )
-1 list one file per line

find /wherever/your/files/hide -type f -exec ls -1rt "{}" +;

Se il comando * esce con uno stato di fallimento (cioè Lista degli argomenti troppo lunga ), allora puoi iterare con find. Parafrasato da: La lunghezza massima degli argomenti per un nuovo processo

  • find . -print0|xargs -0 command (ottimizza la velocità, se find non implementa “-exec +” ma conosce “-print0”)
  • find . -print|xargs command (se non ci sono spazi bianchi negli argomenti)

Se la maggior parte degli argomenti consiste in lunghi percorsi, assoluti o relativi, allora prova a spostare le tue azioni nella directory: cd /directory/with/long/path; command * E un'altra soluzione rapida può essere quella di abbinare meno argomenti: command [a-e]*; command [f-m]*; ...

10
10
10
2012-05-18 07:58:06 +0000

Hai solo bisogno di ls

Potresti fare find /wherever/your/files/hide -type f -exec ls -1rt "{}" +; come detto sopra,

o

ls -1rt `find /wherever/your/file/hides -type f`
8
8
8
2014-04-24 08:12:01 +0000

Estensione della risposta di user195696 :

find . -type f -printf "%T@\t%Tc %6k KiB %p\n" | sort -n | cut -f 2-

Per ogni file, questo emette prima il timestamp numerico (per l'ordinamento in base, seguito dalla tabulazione \t), poi un timestamp leggibile dall'uomo, poi la dimensione del file (purtroppo find non può fare in mebibyte, solo kibibyte), poi il nome del file con percorso relativo.

Poi -printf lo ordina per il primo campo numerico.

Poi sort -n si libera del primo campo numerico che non interessa all'utente. (Stampa il secondo campo in avanti.) Il separatore di campo predefinito è cut o la tabulazione.

Esempio di output:

Thu 06 Feb 2014 04:49:14 PM EST 64 KiB ./057_h2_f7_10/h2_f7_10.class
Fri 07 Feb 2014 02:08:30 AM EST 7962976 KiB ./056_h2_f7_400/h2__rh_4e-4.mph
Fri 07 Feb 2014 02:23:24 AM EST 7962976 KiB ./056_h2_f7_400/h2_f7_400_out_Model.mph
Fri 07 Feb 2014 02:23:24 AM EST 0 KiB ./056_h2_f7_400/h2_f7_400_out.mph.status
Fri 07 Feb 2014 02:23:24 AM EST 64 KiB ./056_h2_f7_400/1579678.out
Fri 07 Feb 2014 03:47:31 AM EST 8132224 KiB ./057_h2_f7_10/h2__rh_1e-5.mph
Fri 07 Feb 2014 04:00:49 AM EST 8132224 KiB ./057_h2_f7_10/h2_f7_10_out_Model.mph
Fri 07 Feb 2014 04:00:49 AM EST 0 KiB ./057_h2_f7_10/h2_f7_10_out.mph.status
Fri 07 Feb 2014 04:00:49 AM EST 64 KiB ./057_h2_f7_10/1579679.out
Fri 07 Feb 2014 09:47:18 AM EST 9280 KiB ./056_h2_f7_400/h2__rh_4e-4.mat
Fri 07 Feb 2014 10:51:23 AM EST 9728 KiB ./018_bidomain/h2_plain__rh_1e-5.mat
Fri 07 Feb 2014 10:58:33 AM EST 9568 KiB ./057_h2_f7_10/h2__rh_1e-5.mat
Fri 07 Feb 2014 05:05:38 PM EST 64 KiB ./058_h2_f7_stationary/h2_f7_stationary.java
Fri 07 Feb 2014 06:06:29 PM EST 32 KiB ./058_h2_f7_stationary/slurm.slurm
Sat 08 Feb 2014 03:42:07 AM EST 0 KiB ./058_h2_f7_stationary/1581061.err
Sat 08 Feb 2014 03:42:14 AM EST 64 KiB ./058_h2_f7_stationary/h2_f7_stationary.class
Sat 08 Feb 2014 03:58:28 AM EST 70016 KiB ./058_h2_f7_stationary/h2s__rh_1e-5.mph
Sat 08 Feb 2014 04:12:40 AM EST 70304 KiB ./058_h2_f7_stationary/h2s__rh_4e-4.mph
Sat 08 Feb 2014 04:12:53 AM EST 70304 KiB ./058_h2_f7_stationary/h2_f7_stationary_out_Model.mph
Sat 08 Feb 2014 04:12:53 AM EST 0 KiB ./058_h2_f7_stationary/h2_f7_stationary_out.mph.status
Sat 08 Feb 2014 04:12:53 AM EST 32 KiB ./058_h2_f7_stationary/1581061.out
Mon 10 Feb 2014 11:40:54 AM EST 224 KiB ./058_h2_f7_stationary/h2s__rh_4e-4.mat
Mon 10 Feb 2014 11:42:32 AM EST 224 KiB ./058_h2_f7_stationary/h2s__rh_1e-5.mat
Mon 10 Feb 2014 11:50:08 AM EST 32 KiB ./plot_grid.m

Ho deliberatamente reso il campo filesize di 6 caratteri, perché se lo si fa più lungo, diventa difficile distinguere visivamente quanto sono grandi i file. In questo modo, i file più grandi di 1e6 KiB sporgono: per 1 carattere significa 1-9 GB, per 2 caratteri significa 10-99 GB, ecc.


Modifica: ecco un'altra versione (dato che \t va in crash su MinGW/MSYS):

find . -type f -printf "%T@\t%p\n" | sort -n | cut -f 2- | xargs -I{} ls -Glath --si {}

Dando output come:

-rw-r--r-- 1 es 23K Jul 10 2010 ./laptop_0000071.jpg
-rw-r--r-- 1 es 43M Jul 29 19:19 ./work.xcf
-rw-r--r-- 1 es 87K Jul 29 20:11 ./patent_lamps/US Patent 274427 Maxim Lamp Holder.jpg
-rw-r--r-- 1 es 151K Jul 29 20:12 ./patent_lamps/Edison screw-in socket.png
-rw-r--r-- 1 es 50K Jul 29 20:13 ./patent_lamps/1157 Lamp.jpg
-rw-r--r-- 1 es 38K Jul 29 20:14 ./patent_lamps/US06919684-20050719-D00001.png

dove:

  • find . -printf "%Tc" fa sì che ogni occorrenza di -I{} sia sostituita da un argomento, e i newline sono ora i separatori degli argomenti (notare gli spazi nei nomi dei file sopra).

  • {} sopprime la stampa del nome del gruppo (spreco di spazio).

  • ls -G produce dimensioni di file leggibili dall'uomo (più corretto con ls -h --si).

  • --si ordina per tempo, che è irrilevante qui, ma è quello che uso di solito.

4
4
4
2016-02-24 15:18:34 +0000

Variante OS X della risposta di @user195696:

  1. Con timestamp:

  2. Senza timestamp:

2
2
2
2019-03-12 19:32:27 +0000

Ho una soluzione semplice che funziona sia per FreeBSD (OS X) che per Linux:

find . -type f -exec ls -t {} +
2
2
2
2012-07-26 07:42:44 +0000

Ho trovato questo che fa il lavoro su Mac OS X (e abbastanza generico da funzionare anche su altri Unixen):

find . -type f -ls | awk '{print $(NF-3), $(NF-2), $(NF-1), $NF}' | sort
1
1
1
2013-12-08 09:14:14 +0000

Usa:

find . -type f -mtime 0 -printf "[%TD %TI:%TM%Tp] %s %p\n" | sort -n | awk '{
    hum[1024**4]="TB"; hum[1024**3]="GB"; hum[1024**2]="MB"; hum[1024]="KB"; hum[0]="B";
    for (x=1024**4; x>=1024; x/=1024){
    if ($3>=x) { printf $1" "$2"\t%7.2f %s\t%s\n",$3/x,hum[x],$4;break }
    }}';

Questo comando ordinerà i file per data di modifica.

E visualizza come:

[12/05/13 03:10PM] 1.75 MB ./file.text
[12/06/13 11:52PM] 2.90 MB ./file2.mp4
[12/07/13 04:11PM] 4.88 MB ./file3.mp4
[12/07/13 09:17PM] 4.74 MB ./test.apk
1
1
1
2014-05-02 11:16:59 +0000

Se la vostra selezione find è molto semplice, potreste farne a meno e usare solo ls:

ls -1 *.cc # -r -t optional
0
0
0
2014-07-04 14:58:50 +0000

Ho migliorato la risposta di Akashs facendo in modo che lo script gestisca correttamente gli spazi bianchi nei nomi dei file:

find . -type f -mtime 0 -printf ";[%TD %TI:%TM%Tp];%s;%p\n" | sort -n | awk -F ";" '{
    hum[1024**4]="TB"; hum[1024**3]="GB"; hum[1024**2]="MB"; hum[1024]="KB"; hum[0]="B";
    for (x=1024**4; x>=1024; x/=1024){
    if ($3>=x) { printf $1" "$2"\t%7.2f %s\t%s\n",$3/x,hum[x],$4;break }
    }}';
0
0
0
2019-09-11 08:23:43 +0000

C'è un modo pulito e robusto di sort | head per data:

Usando ls -l per una bella stampa

find . ! -type d -printf "%T@ %p```
findByDate() {
    local humansize=''
    ["$1" = "-h"] && humansize='h' && shift
    find . ${2:-! -type d} -printf "%T@ %p```
Usage: findByDate [-h] [lines] [find options]
```" |
        sort -zrn |
        head -zn ${1:--0} |
        sed -z 's/^[0-9.] //' |
        xargs -0 ls -dlt${humansize}
}
```" |
    sort -zrn |
    head -zn 10 |
    sed -z 's/^[0-9.] //' |
    xargs -0 ls -lt

Come una funzione bash :

findByDate

Questo potrebbe essere eseguito con uno o due argomenti, o anche senza:

findByDate -h 12

Esempio:

findByDate 42 '-type l'

Elencherà tutte le non directory ordinate per data. Nota:

Anche su un grande albero di filesystem, poiché xargs riceve una lista già ordinata, l'ordine dei file rimane corretto, anche se ls deve essere eseguito molte volte.

findByDate -0 '( -type l -o -type b -o -type s -o -type c )'

Elencherà altri 12 recenti non directory ordinati per data, con la dimensione stampata in forma umanamente leggibile

findByDate() {
    local humansize=''
    ["$1" = "-h"] && humansize='h' && shift
    find . ${2:-! -type d} -printf "%T@ %p```
Usage: findByDate [-h] [lines] [find options]
```" |
        sort -zn |
        tail -zn ${1:-+0} |
        sed -z 's/^[0-9.] //' |
        xargs -0 ls -dltr${humansize}
}

Elencherà altri 42 recenti symlink

0x1&

Elencherà tutti i symlink, dispositivi a blocchi, socket e dispositivi a caratteri, ordinati per data.

Invertire l'ordine

Sostituire head con tail e cambiare il cambio di sort e ls:

0x1&

Stessa funzione, stesso uso:

0x1&

0
0
0
2011-06-07 18:33:10 +0000

Non credo che find abbia alcuna opzione per modificare l'ordinamento dell'output. -mtime e -mmin ti permetteranno di restringere i risultati ai file che sono stati modificati entro una certa finestra temporale, ma l'output non sarà ordinato - dovrai farlo tu stesso. GNU find ha un'opzione -printf che, tra le altre cose, ti permetterà di stampare il tempo di modifica di ogni file trovato (formato stringhe %t o %Tk); questo potrebbe aiutarti a ordinare l'output di find nel modo che desideri.

0
0
0
2018-06-24 23:33:20 +0000

Potete usare stat su BSD e Linux (non su POSIX) in questo modo:

$ stat -f "%m%t%N" /[the dir]/* | sort -rn | cut -f2-

Se volete limitare il numero:

$ stat -f "%m%t%N" /[the dir]/* | sort -rn | head -[the number] | cut -f2-
0
0
0
2014-05-17 10:55:57 +0000

Se volete ordinare tutti i file PNG per tempo in $PWD:

Questo semplice one-liner dà tutta la flessibilità della regexp su find e su ls.

find $PWD -name "*.png" -print0 | xargs -0 ls -laht | less
-1
-1
-1
2017-03-28 01:13:40 +0000

Se volete solo ottenere un percorso completo di ogni elemento potete scrivere così.

find FIND_ROOT -maxdepth 1 -type f -printf "%T@ %p\n" | sort -nr | head -10 | cut -d ' ' -f 2

dove -printf “%T@ %p\n ” per dare un criterio di ordinamento (data), ‘sort -nr’ per ordinare per data, head -10 per elencare i primi 10 risultati, cut -d ‘ ’ -f 2 per tagliare il timestamp iniziale su ogni riga.

-3
-3
-3
2017-03-25 09:09:59 +0000

Ho una soluzione semplice.

Dopo cd in una directory, usate

find . -iname "*" -ls