Unix / Linux localiza e ordena por data modificada

118

Como posso fazer um simples find , que ordenaria os resultados modificados mais recentemente?

Aqui está o atual find que estou usando (estou fazendo um shell escape no PHP, então esse é o raciocínio para as variáveis):

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

Como eu poderia ter esse pedido modificado pela pesquisa mais recente? (Nota Eu não quero que ele classifique 'depois' da procura, mas sim encontre os resultados baseados no que foi modificado mais recentemente.)

    
por Peter Mortensen 07.06.2011 / 20:23

17 respostas

126

Use isto:

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

printf argumentos de man find :

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

  • @ : segundos desde 1º de janeiro de 1970, 00:00 GMT, com parte fracionária.

  • c : data e hora do local (Sábado, 04 de novembro, 12:02:33 EST, 1989).

  • %p : nome do arquivo.

por 05.02.2013 / 14:31
81

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

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

Se você tiver o GNU find, faça-o imprimir os tempos de modificação do arquivo e classifique 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 você tiver o GNU, mas não outros utilitários GNU, use novas linhas como separadores ao invés de nulos; você perderá o suporte para nomes de arquivos contendo novas linhas.

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 você tem Perl (aqui eu assumirei que não há novas linhas nos nomes dos arquivos):

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

Se você tem Python (também assumindo que não há novas linhas em nomes de arquivos):

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

Provavelmente existe uma maneira de fazer o mesmo no PHP, mas eu não sei.

Se você quiser trabalhar apenas com ferramentas POSIX, é um pouco mais complicado; veja Como listar arquivos ordenados por data de modificação recursivamente (nenhum comando stat disponível!) (retrair os 10 primeiros é a parte fácil).

    
por 07.06.2011 / 20:39
37

Você não precisa usar PHP nem 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 status de falha (ou seja, Lista de argumentos muito longa ), você poderá iterar com a localização. Parafraseado a partir de: O tamanho máximo de argumentos para um novo processo

  • find . -print0|xargs -0 command (otimiza velocidade, se achado não implementa "-exec +" mas sabe "-print0")
  • find . -print|xargs command (se não houver espaço em branco nos argumentos)

Se a maior parte dos argumentos consistir em caminhos longos, absolutos ou relativos, tente mover suas ações para o diretório: cd /directory/with/long/path; command * E outra correção rápida pode corresponder a menos argumentos: command [a-e]*; command [f-m]*; ...

    
por 16.06.2011 / 20:11
9

Você precisa apenas de ls

Você pode fazer find /wherever/your/files/hide -type f -exec ls -1rt "{}" +; conforme indicado acima,

ou

ls -1rt 'find /wherever/your/file/hides -type f'
    
por 18.05.2012 / 09:58
6

Estendendo a resposta do user195696 :

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

Para cada arquivo, primeiro ele exibe o registro de data e hora numérico (para classificação por, seguido por tabulação \t ), um registro de data e hora legível e, em seguida, o tamanho do arquivo (infelizmente find ' -printf não pode fazer em mebibytes, apenas kibibytes), então o nome do arquivo com o caminho relativo.

Então sort -n classifica pelo primeiro campo numérico.

Então cut se livra daquele primeiro campo numérico que não é de interesse do usuário. (Imprime o segundo campo em diante.) O separador de campo padrão é \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

Eu deliberadamente fiz o campo do tamanho do arquivo 6 caracteres, porque se ficar mais longo, torna-se difícil distinguir visualmente o tamanho dos arquivos. Desta forma, os arquivos maiores que 1e6 KiB sobressaem: por 1 char significa 1-9 GB, por 2 chars significa 10-99 GB, etc.

Edit: aqui está outra versão (já que find . -printf "%Tc" falha no 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 (observe os espaços nos nomes de arquivos acima).

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

  • ls -h --si produz tamanhos de arquivo legíveis para humanos (mais correto com --si ).

  • ls -t classifica por hora, o que é irrelevante aqui, mas é o que eu geralmente uso.

por 24.04.2014 / 10:12
3

Variante do OS X da resposta do @ user195696:

  1. com timestamp:

    find . -type f -exec stat -f "%Sm %N" -t "%Y%y%m%d%H%M" {} \; | sort -r
    
  2. Sem timestamp:

    find . -type f -exec stat -f "%Sm %N" -t "%Y%y%m%d%H%M" {} \; | sort -r | awk -F' ' '{ print substr($0, length($1) + 2) }'
    
por 24.02.2016 / 16:18
1

Descobri que isso funciona no Mac OS X (e genérico o bastante para funcionar em outros Unixen também):

find . -type f -ls | awk '{print $(NF-3), $(NF-2), $(NF-1), $NF}' | sort
    
por 26.07.2012 / 09:42
1

Se a sua seleção de find for muito simples, você pode conseguir sem ela e usar apenas ls :

ls -1 *.cc # -r -t optional
    
por 02.05.2014 / 13:16
1

Uso:

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 irá ordenar os arquivos por data de modificação.

E exiba 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
    
por 08.12.2013 / 10:14
1

Tente:

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

Mas também é útil filtrar dados por -mmin / -mtime e -type .

    
por 07.06.2011 / 20:31
0

Eu tenho uma solução simples que funciona tanto para o FreeBSD (OS X) quanto para o Linux:

find . -type f -exec ls -t {} +
    
por 12.03.2019 / 20:32
0

Eu não acho que find tenha opções para modificar a ordem de saída. -mtime e -mmin permitem restringir os resultados a arquivos que foram modificados dentro de uma determinada janela de tempo, mas a saída não será classificada - você terá que fazer isso sozinho. O% GNUfind tem uma opção -printf que, entre outras coisas, permitirá que você imprima o horário de modificação de cada arquivo encontrado (formato strings %t ou %Tk ); isso pode ajudá-lo a classificar a saída find da maneira que você deseja.

    
por 07.06.2011 / 20:33
0

Eu melhorei a resposta do Akash ao fazer o script manipular o espaço em branco nos nomes de arquivo corretamente:

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 }
    }}';
    
por 04.07.2014 / 16:58
0

Se você quiser solicitar todos os arquivos PNG por vez em $PWD :

Este simples one-liner dá toda a flexibilidade de regexp em find e em ls .

find $PWD -name "*.png" -print0 | xargs -0 ls -laht | less
    
por 17.05.2014 / 12:55
0

Você 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 você quiser limitar o número:

$ stat -f "%m%t%N" /[the dir]/* | sort -rn | head -[the number] | cut -f2-
    
por 25.06.2018 / 01:33
-1

Se você quiser apenas um caminho 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

Em que lugar -printf "% T @% p \ n" para dar os critérios de ordenação (data),
'sort -nr' para ordenação por data,
head -10 para listar os 10 melhores resultados, cut -d '' -f 2 para cortar o timestamp principal em cada linha.

    
por 28.03.2017 / 03:13
-3

Eu tenho uma solução simples.

Depois de cd para um diretório, use

find . -iname "*" -ls

    
por 25.03.2017 / 10:09