Encontre o arquivo mais recente por data de modificação

39

Se eu quiser encontrar o arquivo mais recente (mtime) em um diretório (grande) contendo subdiretórios, como eu faria isso?

Muitas postagens que encontrei sugerem alguma variação ls -lt | head(divertidamente, muitas sugerem ls -ltr | tailque é a mesma, mas menos eficiente), o que é bom, a menos que você tenha subdiretórios (eu tenho).

Então, novamente, você poderia

find . -type f -exec ls -lt \{\} \+ | head

o que definitivamente fará o truque para quantos arquivos puderem ser especificados por um comando, ou seja, se você tiver um diretório grande , -exec...\+emitirá comandos separados; portanto, cada grupo será classificado lsdentro de si, mas não no conjunto total; portanto, o cabeçote coletará a última entrada do primeiro lote.

Alguma resposta?

Rico
fonte
Aliás, você não precisa de nenhuma dessas barras invertidas.
enzotib 13/09/11
@enzotib: você faz ( \ + ), caso contrário você obtémfind: missing argument to '-exec'
organize
@range: Eu não tenho esse erro, pois +não tem significado para bash, então não há necessidade de escapar dele.
enzotib 13/09/11
@enzotib: você está certo, meu erro, desculpe
organize

Respostas:

46

Você não precisa recorrer a comandos externos (as ls) porque findpode fazer tudo o que precisa através da -printfação:

find /path -printf '%T+ %p\n' | sort -r | head
enzotib
fonte
1
Sim, eu criei, find . -type f -exec stat --format=%y \{\} \+ | sort -r | head -n1mas sua solução é muito mais limpa!
Rich
3
Anexar | cut -d ' ' -f2para obter apenas o nome do arquivo
qwr
Você também pode selecionar a saída headpara incluir um certo número de linhas. Eu só precisava da primeira linha, então useihead -n 1
Timmah 28/04
8

Eu tive um problema semelhante hoje, mas o ataquei sem find. Eu precisava de algo curto para sshpoder retornar o arquivo editado mais recentemente no meu diretório pessoal. Isto é aproximadamente o que eu vim com:

ls -tp | grep -v /$ | head -1

A -popção de lsadicionar uma barra final aos diretórios, grep -vremove as linhas que terminam em uma barra (também conhecida como todos os diretórios) e head -1limita a saída a um único arquivo.

Isso é muito menos detalhado do que usar findse tudo o que você deseja retornar é o nome do arquivo.

Pat Regan
fonte
Isso não lida com subdiretórios.
Clément
4

Isso está no meu sistema mais rápido que printf, embora eu não entenda por que

find /path -type f -exec stat -c "%y %n" {} + | sort -r | head
organizar
fonte
Eu confirmo, é mais rápido.
enzotib 13/09/11
Mais um ponto, ... | sort -r | head -n1 | cut -d " " -f 4-se você deseja obter apenas o nome do arquivo.
precisa saber é
Acabei de encontrar sort -rerrado se o nome do arquivo em várias linhas existir.
林果皞
2

Edição: Eu acho que este post não é 'particularmente útil' como eu pensava que era. Esta é uma solução realmente rápida que apenas rastreia o arquivo modificado mais recentemente (em vez de classificar a lista inteira de arquivos):

find . -type f -printf '%T@ %p\n' | awk 'BEGIN { mostrecenttime = 0; mostrecentline = "nothing"; } { if ($1 > mostrecenttime) { mostrecenttime = $1; mostrecentline = $0; } } END { print mostrecentline; }' | cut -f2- -d ' '

Espalhe por várias linhas para maior clareza:

find . -type f -printf '%T@ %p\n' | awk '
    BEGIN { mostrecenttime = 0; mostrecentline = "nothing"; }
    {
        if ($1 > mostrecenttime)
            { mostrecenttime = $1; mostrecentline = $0; }
    }
    END { print mostrecentline; }' | cut -f2- -d ' '

Fim da edição


Não é um post particularmente útil, mas como 'organizar' estava discutindo velocidade, pensei em compartilhar isso.

As soluções de arranjo e enzotib envolvem a listagem de todos os arquivos dentro do diretório com seus respectivos tempos e classificação. Como você sabe, a classificação não é necessária para encontrar o máximo. Encontrar o máximo pode ser feito em tempo linear, mas a classificação leva n log (n) tempo [eu sei que a diferença não é muito, mas ainda assim;)]. Não consigo pensar em uma maneira elegante de implementar isso. [EDIT: Uma implementação limpa (embora com aparência desagradável) e rápida fornecida acima.]

Próxima melhor coisa - Para encontrar o arquivo editado mais recentemente em um diretório, localize recursivamente o arquivo editado mais recentemente em cada subdiretório de nível 1. Deixe este arquivo representar o subdiretório. Agora classifique os arquivos de nível 1, juntamente com os representantes dos subdiretórios de nível 1. Se o número de arquivos de nível 1 e subdiretórios de cada diretório for quase constante, esse processo deverá ser dimensionado linearmente com o número total de arquivos.

Isto é o que eu vim para implementar isso:

findrecent() { { find "$1" -maxdepth 1 -type f -exec stat -c "%y %n" {} + | sort -r | head -1 && find "$1" -mindepth 1 -maxdepth 1 -type d -exec findrecent {} \;; } | sort -r | head -1; }
findrecent .

Corri isso e recebi um monte de find: findrecent: No such file or directoryerros. Razão: -exec de find é executado em um shell diferente. Eu tentei definir findrecent em .bashrc, .xsessionrc, mas estes não ajudaram [eu apreciaria a ajuda aqui]. No final, eu recorri a colocar

#!/bin/bash
{ find "$1" -maxdepth 1 -type f -exec stat -c "%y %n" {} + | sort -r | head -1 && find "$1" -mindepth 1 -maxdepth 1 -type d -exec findrecent {} \;; } | sort -r | head -1;

em um script chamado findrecentno meu PATH e depois executá-lo.

Eu executei isso, continuei esperando e sem saída. Só para ter certeza de que não estava lidando com nenhum loop infinito, modifiquei o arquivo para

#!/bin/bash
echo "$1" >&2
{ find "$1" -maxdepth 1 -type f -exec stat -c "%y %n" {} + | sort -r | head -1 && find "$1" -mindepth 1 -maxdepth 1 -type d -exec findrecent {} \;; } | sort -r | head -1;

e tentei novamente. Funcionou - mas demorou 1 minuto e 35 segundos na minha pasta - as soluções do arranjo e do enzotib levaram 1,69, 1,95 segundos, respectivamente!

Tanto pela superioridade de O (n) sobre O (n log (n))! Droga, você trabalha com a chamada em cima! [Ou melhor, sobrecarga de chamada de script]

Mas esse script é melhor que as soluções anteriores e aposto que ele será executado mais rapidamente do que eles no banco de memória do Google; D

S Prasanth
fonte
2

Use perlem conjunto com find:

 find my_directory -type f -printf '%T@\t%p\n' | perl -ane '@m=@F if ($F[0]>$m[0]); END{print $m[1];}'

Você obtém o nome do arquivo com a maior época == último arquivo modificado.

MUY Bélgica
fonte
1

Não está tão na moda, mas também é possível conseguir isso com o Midnight Commander : pesquise *, organize o resultado, classifique por tempo de modificação na ordem inversa.

Obviamente, é um pouco mais lento que find- meu diretório pessoal, contendo 922000 arquivos, foi classificado mcem quase 14 minutos enquanto findgasto menos de 5 - mas há alguns benefícios:

  • Eu provavelmente gastaria mais tempo do que a diferença de 9 minutos inventando uma chamada de localização adequada :)

  • menor chance de erro (esqueceu de especificar -r para classificação etc. - comece novamente)

  • é possível jogar com o conjunto de resultados alterando a ordem de classificação etc. - sem consultar novamente os arquivos.

  • possível executar operações de arquivo apenas em alguns arquivos do conjunto de resultados - ou seja, classificar por tamanho, excluir alguns arquivos grandes que não são necessários

Sergey
fonte