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

Unix/Linux encontrar e ordenar por data modificada

Como posso fazer um simples find que encomendaria os resultados pela última modificação?

Aqui está o actual find que estou a utilizar (estou a fazer uma fuga de shell em PHP, por isso esse é o raciocínio para as variáveis):

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

Como poderia encomendar a pesquisa pela última modificação? (Nota: não quero que ordene ‘depois’ da pesquisa, mas sim que encontre os resultados com base no que foi modificado mais recentemente).

Respostas (17)

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

Use isto:

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

printf argumentos de man find :

  • %Tk: Tempo da última modificação do ficheiro no formato especificado por k.

  • @: segundos desde 1 de Janeiro de 1970, 00:00 GMT, com parte fracionada.

  • c&: data e hora do locale (Sábado Nov 04 12:02:33 EST 1989).

  • %p: Nome do ficheiro.

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

O método mais fácil é usar zsh, graças aos seus glob qualifiers .

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

Se tiver o GNU find, faça-o imprimir os tempos de modificação do ficheiro e ordene-o por isso.

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 tiver o GNU find mas não outros utilitários GNU, use linhas novas como separadores em vez de nulos; perderá o suporte para nomes de ficheiros contendo linhas novas.

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 tiver Perl (aqui vou assumir que não há novas linhas em nomes de ficheiros):

0x1&

Se tiver Python (assumindo também que não há novas linhas em nomes de ficheiros):

0x1&

Há provavelmente uma forma de fazer o mesmo em PHP, mas não o conheço.

Se quiser trabalhar apenas com ferramentas POSIX, é bastante mais complicado; ver Como listar ficheiros ordenados por data de modificação recursivamente (nenhum comando stat disponível!) (retatinar os primeiros 10 é a parte fácil).

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

Não precisa de PHP ou Python, apenas 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 o comando * sair com um estado de falha (ou seja Lista de documentos demasiado longa* ), então pode iterar com find. Parafraseado de: A duração máxima dos argumentos para um novo processo

  • find . -print0|xargs -0 command (optimiza a velocidade, se o find não implementa “-exec +” mas sabe “-print0”)
  • find . -print|xargs command (se não houver espaço branco nos argumentos)

Se a maior parte dos argumentos consiste em caminhos longos, absolutos ou relativos, então tente mover as suas acções para o directório: cd /directory/with/long/path; command *& E outra solução rápida pode ser a de combinar menos argumentos: command [a-e]*; command [f-m]*; ...

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

Só precisa de ls

Pode fazer find /wherever/your/files/hide -type f -exec ls -1rt "{}" +; como indicado acima,

ou

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

Estendendo resposta do utilizador195696 :

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

Para cada ficheiro, este primeiro emite o carimbo temporal numérico (para ordenação por, seguido de tabulação \t), depois um carimbo temporal legível por humanos, depois os ficheiros são dimensionados (infelizmente find‘s -printf não pode fazer em mebibibytes, apenas kibibibytes), depois o nome do ficheiro com caminho relativo.

depois sort -n ordena-o pelo primeiro campo numérico.

Depois cut livra-se desse primeiro campo numérico que não tem interesse para o utilizador. (Imprime o segundo campo em frente.) O separador de campo por defeito é \t& ou tabulação.

Exemplo de saída:

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

Fiz deliberadamente os ficheiros com 6 caracteres, porque se o tornar mais longo, torna-se difícil distinguir visualmente o tamanho dos ficheiros. Desta forma, os ficheiros maiores que 1e6 KiB saltam fora: por 1 char significa 1-9 GB, por 2 chars significa 10-99 GB, etc.


Editar: aqui está outra versão (desde find . -printf "%Tc" falha em MinGW/MSYS):

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

Dar saída como:

-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

Onde:

  • -I{} faz com que a ocorrência de {} seja substituída por um argumento, e novas linhas são agora os separadores de argumentos (note os espaços em nomes de ficheiro acima).

  • ls -G suprime a impressão do nome do grupo (desperdício de espaço).

  • ls -h --si produz tamanhos de ficheiro legíveis por humanos (mais correcto com --si).

  • ls -t ordena por tempo, o que aqui é irrelevante, mas é o que normalmente uso.

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

Variante OS X da resposta de @user195696:

  1. com timestamp:

  2. Sem carimbo de data/hora:

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

Tenho uma solução simples que funciona tanto para FreeBSD (OS X) como para Linux:

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

Descobri que isto faz o trabalho em Mac OS X (e suficientemente genérico para trabalhar também em outros 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

Utilização:

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 }
    }}';

Este comando ordenará os ficheiros por data modificada.

E exibir como:

[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 a sua selecção find é muito simples, poderá passar sem ela, e usar apenas ls:

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

Melhorei a resposta do Akashs ao fazer o guião manipular correctamente os espaços em branco nos nomes dos ficheiros:

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

Existe uma forma limpa e robusta de sort | head por data:

Usando ls -l para uma bonita impressão

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

Como uma função bash :

findByDate

Isto pode ser executado com um ou dois argumentos, ou mesmo sem:

findByDate -h 12

Amostra:

findByDate 42 '-type l'

Lista todos os non directórios ordenados por data. Nota:

Mesmo em grandes árvores de sistemas de ficheiros, uma vez que xargs já recebem a lista ordenada, a ordem dos ficheiros permanece correcta, mesmo que ls tenha de ser executada muitas vezes.

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

Listará mais 12 recentes non directórios ordenados por data, com tamanho impresso em forma humana legível

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}
}

Listará mais 42 recentes symlinks

0x1&

Listará todos os symlinks, dispositivos de bloco, tomadas e dispositivos de caracteres, ordenados por data.

Ordem de inversão

Substituindo head por tail e mudança de interruptor de sort e ls:

0x1&

mesma função, mesmo uso: por

0x1&

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

Não creio que find tenha quaisquer opções para modificar o pedido de saída. O -mtime e o -mmin permite-lhe restringir os resultados a ficheiros que tenham sido modificados dentro de uma determinada janela de tempo, mas a saída não será ordenada - terá de o fazer você mesmo. GNU find tem uma opção -printf que, entre outras coisas, lhe permitirá imprimir o tempo de modificação de cada ficheiro encontrado (formatar cordas %t ou %Tk); isso poderá ajudá-lo a ordenar a saída find da forma que desejar.

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

Pode usar stat no BSD e Linux (não no POSIX) desta forma:

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

Se quiser limitar o número:

$ 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 quiser encomendar todos os ficheiros PNG por tempo em $PWD:

Esta simples linha única dá toda a flexibilidade de regexp em find e em ls.

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

Se quiser apenas obter um percurso completo de cada item, pode escrever assim.

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

Onde -printf “%T@ %p\n ” para dar critérios de ordenação (data), ‘ordenar -nr’ para ordenar por data, cabeça -10 para listar os 10 melhores resultados, cut -d ‘ ’ -f 2 para cortar o carimbo da hora principal em cada linha.

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

Tenho uma solução simples.

Após cd para um directório, usar

find . -iname "*" -ls.