Unix / Linux encontra e classifica por data de modificação

138

Como posso fazer um simples findque ordenaria os resultados pela última modificação?

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

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

Como eu poderia ter essa ordem modificada pela pesquisa mais recentemente? (Observe que não quero que ele classifique 'depois' da pesquisa, mas encontre os resultados com base no que foi modificado mais recentemente).

Peter Mortensen
fonte
github.com/shadkam/recentmost faria o que é desejado - mas é preciso construí-lo
user3392225

Respostas:

153

Usa isto:

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

printfargumentos 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 da localidade (Sáb 04 de novembro 12:02:33 EST 1989).

  • %p: Nome do arquivo.

user195696
fonte
5
+1 Muito útil, a primeira resposta a esta eu encontrei com uma saída de data legível / útil
Jake N
mais confiável (e muito simples), pois o tempo é concedido para ser numericamente seqüencial (portanto, sempre adequadamente ordenável), thx!
Aquarius Power
11
Eu tenho esse alias para encontrar arquivos recentes no meu ~/.zshrc: fr () { find ./ -iname "*"$@"*" -printf "%T@ %Td-%Tb-%TY %Tk:%TM %p\n" | sort -n | cut -d " " -f 2- | grep -i "$@" ; }Ele encontra recursivamente todos os arquivos que contêm o padrão do primeiro argumento passado ao comando ( fr <pattern>) e os classifica com o último mais recente.
Joelostblom 27/10/16
Isso é ótimo !!! Para usar com links simbólicos, usefind -L ...
Varun Chandak
11
Você pode usar ssedpara se livrar da parte fracionária de segundos e ainda usar a ISO8601, como @ PeterMortensen mostrou:find . -type f -printf "%TY-%Tm-%TdT%TT %p\n" | sort -r | ssed -R 's/^([^.]+)\.\d+ (.*)$/\1 \2/'
Ludovic Kuty
83

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

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

Se você encontrar o GNU, faça-o imprimir os tempos de modificação do arquivo e classifique-os de acordo com isso.

find -type f -printf '%T@ %p\0' |
sort -zk 1nr |
sed -z 's/^[^ ]* //' | tr '\0' '\n' | head -n 10

Se você tiver o GNU find, mas não outros utilitários do GNU, use novas linhas como separadores em vez de nulos; você perderá o suporte para nomes de arquivos contendo novas linhas.

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

Se você possui Perl (aqui assumirei que não há novas linhas nos nomes dos arquivos):

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

Se você possui Python (também assumindo que não há novas linhas nos nomes dos arquivos):

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'

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

Se você deseja trabalhar apenas com ferramentas POSIX, é um pouco mais complicado; veja Como listar arquivos ordenados por data de modificação de forma recursiva (nenhum comando de estatísticas disponíveis!) (retatining o primeiro 10 é a parte mais fácil).

Gilles
fonte
Eu acho que a findversão mostra os arquivos mais antigos, e que você precisa adicionar a -ropção sort.
Quentin Pradet
Meu sed diz que não tem uma opção -z.
Kef Schecter
@KefSchecter Em seguida, use as novas linhas como separadores, mas você perderá o suporte para novas linhas nos nomes dos arquivos.
Gilles
O acima é para python2. Se você tiver apenas python3, algumas pequenas alterações: python3 -c 'import os, sys; times = {} para f em sys.stdin.readlines (): f = f [0: -1]; times [f] = os.stat (f) .st_mtime para f in (classificado (times.keys (), key = lambda f: times [f], reverse = True)) [: 10]: print (f); "
Neil McGill
40

Você não precisa de PHP ou Python, apenas sl :

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 (por exemplo, a lista de argumentos é muito longa ), você poderá iterar com a localização. Parafraseado de: O tamanho máximo de argumentos para um novo processo

  • find . -print0|xargs -0 command (otimiza a velocidade, se a localização não implementar "-exec +", mas souber "-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 solução rápida pode ser a de corresponder a menos argumentos:command [a-e]*; command [f-m]*; ...

Ярослав Рахматуллин
fonte
11
Se houver muitos arquivos, isso falhará com 'Lista de argumentos muito longa' no ls.
Occulus 03/09/12
11
Isso é verdade, mas acredito que a pergunta era "como faço para encontrar uma descoberta simples ..."
Sepрослав Рахматуллин
2
se ls não citar nomes de arquivos de uma forma xargs pode entender (sem opção -0, e os vários estilos Citações são inadequados)
Tobu
10

Você só precisa de ls

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

ou

ls -1rt `find /wherever/your/file/hides -type f`
skippy1910
fonte
2
Se houver muitos arquivos, isso falhará com 'Lista de argumentos muito longa' no ls. Talvez recook para usar xargs?
Occulus 03/09/12
2
Mas se xargsligar lsvárias vezes, a classificação será interrompida.
Aaron D. Marasco
Isso falha para arquivos com espaços em seus nomes. Algum conselho?
user74094
Apenas me deparei com essa resposta e era exatamente o que eu precisava em uma situação semelhante. Pergunta: o que +;o final faz? Parece dar o mesmo resultado sem o ;porém não funciona sem o +?
RocketNuts 21/03
É exatamente o mesmo que outra resposta postada 8 meses antes, exceto pela parte sobre o uso de "ls -1rt` find ... `", que está quebrado
Clément
7

Estendendo a resposta de user195696 :

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

Para cada arquivo, isso gera primeiro o carimbo de data / hora numérico (para classificação, seguido por tabulação \t), depois um carimbo de data / hora legível por humanos, depois o tamanho do arquivo (infelizmente findnão é -printfpossível fazer em mebibytes, apenas kibibytes) e o nome do arquivo com caminho.

Em seguida, sort -nclassifica-o pelo primeiro campo numérico.

Em seguida, cutelimina o primeiro campo numérico que não interessa ao usuário. (Imprime o segundo campo em diante.) O separador de campo padrão é \tou 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 criei o campo de tamanho de arquivo com 6 caracteres, porque, se o prolongar, fica difícil distinguir visualmente o tamanho dos arquivos. Dessa forma, arquivos maiores que 1e6 KiB se destacam: por 1 caractere significa 1-9 GB, por 2 caracteres significa 10-99 GB, etc.


Edit: aqui está outra versão (desde find . -printf "%Tc"falhas no MinGW / MSYS):

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

Dando 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 {}seja substituída por um argumento, e as novas linhas agora são os separadores de argumentos (observe os espaços nos nomes de arquivos acima).

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

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

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

Evgeni Sergeev
fonte
11
Nota: para classificar por tamanho do arquivo , basta substituir o T@by sem um dos comandos acima.
Evgeni Sergeev
3

Variante do OS X da resposta de @ user195696:

  1. Com registro de data e hora:

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

    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) }'
    
user9399
fonte
2

Descobri que isso faz o trabalho no Mac OS X (e genérico o suficiente para funcionar em outro Unixen também):

find . -type f -ls | awk '{print $(NF-3), $(NF-2), $(NF-1), $NF}' | sort
Bryan Petty
fonte
2
Infelizmente, isso imprime nomes de meses localizados na minha configuração croata, tornando a classificação incorreta.
Ivan Vučica
A resposta de user195696 funciona para a configuração croata (e outras).
Peter Mortensen
1

Se sua findseleção for muito simples, você poderá ficar sem ela e use ls:

ls -1 *.cc # -r -t optional
djc
fonte
1

Experimentar:

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

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

Peter Mortensen
fonte
1

Usar:

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

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
Akash
fonte
Melhorei este sript para lidar com espaços em branco em nomes de arquivos, consulte superuser.com/a/777007/134532
janeiro
1

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

find . -type f -exec ls -t {} +
Alex Shchur
fonte
Isso funciona perfeitamente - deve ser a resposta correta ou, pelo menos, com uma classificação mais alta!
digitaltoast 14/06
0

Eu acho que não findtem nenhuma opção para modificar a ordem de saída. -mtimee -mminpermitirá 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 GNU findtem uma -printfopção que, entre outras coisas, permite imprimir o tempo de modificação de cada arquivo encontrado (formatar cadeias %tou %Tk); Isso pode ajudá-lo a classificar a findsaída da maneira que desejar.

Jim Lewis
fonte
0

Melhorei a resposta do Akashs, fazendo o script manipular espaços em branco nos nomes de arquivos 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 }
    }}';
jan
fonte
0

Se você deseja solicitar todos os arquivos PNG por hora em $PWD:

Este one-liner simples dá toda a flexibilidade de regexp em finde sobre ls.

find $PWD -name "*.png" -print0 | xargs -0 ls -laht | less
john smith
fonte
0

Você pode usar statno BSD e Linux (não no POSIX) desta maneira:

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

Se você deseja limitar o número:

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

Há uma maneira limpa e robusta de sort | headdata:

Usando ls -lpara impressão bonita

find . ! -type d -printf "%T@ %p\0" |
    sort -zrn |
    head -zn 10 |
    sed -z 's/^[0-9.]\+ //' |
    xargs -0 ls -lt

Como uma função :

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

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

Usage: findByDate [-h] [lines] [find options]

Amostra:

findByDate

Listará todos os diretórios não classificados por data. Nota:

Mesmo na grande árvore do sistema de arquivos, como a xargs lista de recebimento já classificada, a ordem dos arquivos permanece correta, mesmo que lsdeva ser executada várias vezes.

findByDate -h 12

Listará mais 12 diretórios não recentes classificados por data, com o tamanho impresso em formato legível por humanos

findByDate 42 '-type l'

Listará mais 42 links simbólicos recentes

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

Irá listar todos os links simbólicos, dispositivos de bloco, soquetes e caracteres, classificados por data.

Ordem de inversão

Substituir headpor taile mudar interruptor de sorte ls:

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

Mesma função, mesmo uso:

Usage: findByDate [-h] [lines] [find options]
F. Hauri
fonte
-1

Se você quiser apenas obter um caminho completo de cada item, anote 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 fornecer critérios de classificação (data),
'sort -nr' para classificar por data,
head -10 para listar os 10 melhores resultados,
corte -d '' -f 2 para cortar o timestamp inicial em cada linha.

David Jung
fonte
cut -d ' ' -f 2será interrompido se os nomes de arquivos contiverem espaços.
F. Hauri 11/09
-3

Eu tenho uma solução simples.

Depois cdde um diretório, use

find . -iname "*" -ls

cantar
fonte
11
Isso não classifica por data de modificação.
DavidPostill