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.