Come elencare i file ordinati in modo ricorsivo per data di modifica (nessun comando stat disponibile!)


31

Come posso ottenere l'elenco di tutti i file nella directory corrente insieme alla loro data di modifica e ordinati per quella data?

Ora so come raggiungerlo con find, state sort, ma per qualche strana ragione, statnon è installato sulla scatola ed è improbabile che riesca a installarlo.

Qualche altra opzione?

PS: gccneanche installato


Puoi caricare un file binario compilato ed eseguirlo lì?
imz - Ivan Zakharyaschev

@imz: sì, questa è un'altra strada da percorrere. L' find -printfazione sembra essere la più semplice però.
alex

Risposte:


27

Il mio metodo più breve utilizza zsh:

print -rl -- **/*(.Om)

(aggiungi i Dqualificatori glob se vuoi anche elencare i file nascosti o i file nelle directory nascoste).

Se hai GNU find, fallo stampare i tempi di modifica del file e ordina per quello. Presumo che non ci siano nuove righe nei nomi dei file.

find . -type f -printf '%T@ %p\n' | sort -k 1 -n | sed 's/^[^ ]* //'

Se hai Perl (di nuovo, supponendo che non ci siano nuove righe nei nomi dei file):

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

Se hai Python (di nuovo, supponendo che non ci siano nuove righe nei nomi dei file):

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'

Se si dispone dell'accesso SSH a quel server, montare la directory su sshfs su una macchina meglio equipaggiata:

mkdir mnt
sshfs server:/path/to/directory mnt
zsh -c 'cd mnt && print -rl **/*(.Om)'
fusermount -u mnt

Con solo gli strumenti POSIX, è molto più complicato, perché non c'è un buon modo per trovare il tempo di modifica di un file. L'unico modo standard per recuperare i tempi di un file è lse il formato di output dipende dalla locale e difficile da analizzare.

Se riesci a scrivere sui file e ti preoccupi solo dei file normali e non ci sono nuove righe nei nomi dei file, ecco un orribile kludge: creare collegamenti reali a tutti i file in una singola directory e ordinarli in base al tempo di modifica.

set -ef                       # disable globbing
IFS='
'                             # split $(foo) only at newlines
set -- $(find . -type f)      # set positional arguments to the file names
mkdir links.tmp
cd links.tmp
i=0 list=
for f; do                     # hard link the files to links.tmp/0, links.tmp/1, …
  ln "../$f" $i
  i=$(($i+1))
done
set +f
for f in $(ls -t [0-9]*); do  # for each file, in reverse mtime order:
  eval 'list="${'$i'}         # prepend the file name to $list
$list"'
done
printf %s "$list"             # print the output
rm -f [0-9]*                  # clean up
cd ..
rmdir links.tmp

Il modo più semplice è probabilmente find . -print | xargs -n99999 -s999999 ls -ltr. Ma questo ha il problema che (1) xargsnon può consentire un numero -mmaggiore di 512 o -smaggiore di 5120 e (b) anche se riesci a aggirare il problema , c'è ancora una dimensione massima imposta dal kernel dell'elenco di argomenti e dell'ambiente combinati. La maggior parte delle tue idee (salva quelle Perl e Python) hanno lo stesso problema, motivo per cui ho evitato in modo specifico la costruzione di lunghe linee di comando.
geekosaur,

In particolare, ricevo regolarmente errori di "elenco argomenti troppo lunghi" usando zshglobi ricorsivi nel caso generale.
geekosaur,

@geekosaur: solo l'ultimo kludge orribile ha un problema con le lunghe linee di comando. In zsh, puoi fare molto con i built-in (ad esempio print -rl **/*l'unico limite è la quantità di memoria libera che hai) e oltre a ciò c'è zargs. La tua proposta find … | xargs … lsverrà ordinata correttamente se xargsfinisce per invocare lsuna sola volta e non funzionerà se ci sono caratteri speciali nei nomi dei file.
Gilles 'SO-smetti di essere malvagio' il

molte grazie per la risposta estremamente dettagliata con molte opzioni! :)
alex

Ed è per questo che adoro zsh.
Profpatsch,

14

Supponendo GNU find:

find . -printf '%T@ %c %p\n' | sort -k 1n,1 -k 7 | cut -d' ' -f2-

Passare 1n,1a 1nr,1se si desidera prima elencare i file più recenti.

Se non hai GNU find, diventa più difficile perché lsil formato del timestamp varia molto (ad esempio, i file modificati di recente hanno un diverso stile di timestamp).


In realtà puoi anche cambiare il formato di data e ora con ls --time-style="..."- Non sono sicuro che sia standard o GNU, probabilmente GNU.
asoundmove,

Sicuramente GNU.
geekosaur,

@asoundmove: purtroppo la scatola è troppo vecchia (RedHat 7.2) e lsnon ha questa opzione.
alex

7

Su un mac non c'è argomento -printf da trovare, ma puoi farlo invece:

find . -print0 | xargs -0 -n 100 stat -f"%m %Sm %N" | sort -n|awk '{$1="";print}'



0

Ignorare i file nascosti - con timestamp 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.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

Più findbizzeffe si possono trovare seguendo il link.


0

Parlando in genere di trovare i file per data (questo non funzionerà per il poster originale, ma sono finito qui, quindi ho pensato che anche altri potrebbero). Nel mio caso d'uso voglio elencare i file allo scopo di esaminarli prima della cancellazione.

Con findutils 4.6.0 mi piace:

find . -type f -mtime +270 -exec ls -laFGht --time-style=iso {} \+

Il comando precedente trova i file ( -type f), nella directory di lavoro corrente ( .) che sono stati modificati più di 270 giorni fa ( -mtime +270anche -mtime 0produrrà delle ultime 24 ore, e -mtime -5mostra gli ultimi 5 giorni). Quindi utilizza lsper elencarli per data, prima i più recenti ( -exec ls -laFGht --time-style=iso {} \+)

Ecco un esempio dell'output:

-rwxrwx---+ 1 user1 208M 2018-07-16  ./filename.bak*
-rwxrwx---+ 1 user1  702 2018-07-15  ./filename.ldf*
-rwxrwx---+ 1 user1 208M 2018-07-15  ./filename.bak*

Il bello di questo è che una volta che l'elenco è stato rivisto, è semplice sostituire la parte dell'elenco con il findcomando delete:

find . -type f -mtime +270 -delete
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.