Como listar os arquivos classificados por data de modificação recursivamente (nenhum comando stat disponível!)

31

Como posso obter a lista de todos os arquivos no diretório atual, juntamente com a data da modificação e classificados por essa data?

Agora eu sei como conseguir isso com find, state sort, mas por algum motivo estranho, o statnão está instalado na caixa e é improvável que eu possa instalá-lo.

Alguma outra opção?

PS: gcctambém não está instalado

alex
fonte
Você pode carregar um binário compilado e executá-lo lá?
imz - Ivan Zakharyaschev 14/03
@imz: sim, esse é outro caminho a percorrer. A find -printfação parece ser a mais fácil.
alex

Respostas:

27

Meu método mais curto usa zsh:

print -rl -- **/*(.Om)

(adicione os Dqualificadores glob se você também quiser listar os arquivos ocultos ou os arquivos nos diretórios ocultos).

Se você encontrar o GNU, faça-o imprimir os tempos de modificação do arquivo e classifique-os de acordo com isso. Suponho que não haja novas linhas nos nomes dos arquivos.

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

Se você possui o Perl (novamente, assumindo 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";
        print sort {$_{$b} <=> $_{$a}} keys %_;  # print by decreasing age
    }'

Se você possui Python (novamente, 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]): print f'

Se você tiver acesso SSH a esse servidor, monte o diretório sobre sshfs em uma máquina melhor equipada:

mkdir mnt
sshfs server:/path/to/directory mnt
zsh -c 'cd mnt && print -rl **/*(.Om)'
fusermount -u mnt

Com apenas as ferramentas POSIX, é muito mais complicado, porque não há uma boa maneira de encontrar o tempo de modificação de um arquivo. A única maneira padrão de recuperar os horários de um arquivo é lse o formato de saída depende da localidade e é difícil de analisar.

Se você pode gravar nos arquivos e se preocupa apenas com os arquivos regulares, e não há novas linhas nos nomes dos arquivos, aqui está um argumento horrível: crie links físicos para todos os arquivos em um único diretório e classifique-os por tempo de modificação.

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
Gilles 'SO- parar de ser mau'
fonte
A maneira mais fácil é provavelmente find . -print | xargs -n99999 -s999999 ls -ltr. Mas isso tem o problema de que (1) xargsnão pode permitir -mmaior que 512 ou -smaior que 5120 e (b) mesmo que você possa contornar isso, ainda existe um tamanho máximo imposto pela kernel da lista de argumentos e do ambiente combinados. A maioria das suas idéias (exceto as do Perl e Python) tem o mesmo problema, razão pela qual evitei especificamente a construção de longas linhas de comando.
Geekosaur
Em particular, eu recebo regularmente erros da "lista de argumentos muito longos" usando zshglobs recursivos no caso geral.
Geekosaur #
@geekosaur: Apenas o último kludge horrível tem um problema com longas linhas de comando. No zsh, você pode fazer muito com built-ins (por exemplo print -rl **/*, o único limite é a quantidade de memória livre que você possui) e além disso existe zargs. Sua proposta de find … | xargs … lsserá classificada corretamente se xargsacabar invocando lsapenas uma vez e não funcionará se houver caracteres especiais nos nomes dos arquivos.
Gilles 'SO- stop be evil'
muito obrigado pela resposta extremamente detalhada com muitas opções! :)
alex
E é por isso que eu amo zsh.
Profpatsch
14

Assumindo o GNU find:

find . -printf '%T@ %c %p\n' | sort -k 1n,1 -k 7 | cut -d' ' -f2-

Mude 1n,1para 1nr,1se você deseja que os arquivos listados mais recentes primeiro.

Se você não possui o GNU find, fica mais difícil porque lso formato do carimbo de data / hora varia muito (arquivos modificados recentemente têm um estilo diferente de carimbo de data / hora, por exemplo).

geekosaur
fonte
Na verdade, você também pode alterar o formato de data e hora com ls --time-style="..."- não tenho certeza se isso é padrão ou GNU ls, provavelmente GNU.
asoundmove
Definitivamente GNU.
Geekosaur 14/03
@asoundmove: infelizmente, a caixa é muito antiga (RedHat 7.2) e lsnão possui essa opção.
alex
7

Em um mac, não há argumento -printf para encontrar, mas você pode fazer isso:

find . -print0 | xargs -0 -n 100 stat -f"%m %Sm %N" | sort -n|awk '{$1="";print}'

killdash9
fonte
0

pode-se tentar isso (é preciso construir por conta própria) https://github.com/shadkam/recentmost

user3392225
fonte
6
Bem-vindo ao Unix e Linux Stack Exchange! Embora isso possa teoricamente responder à pergunta, seria preferível incluir aqui as partes essenciais da resposta e fornecer o link para referência.
slm
0

Ignorando arquivos ocultos - com carimbo de tempo agradável e rápido

Lida bem com espaços nos nomes de arquivos - não que você deva usá-los!

$ 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

findPode encontrar mais abundância seguindo o link.

Serge Stroobandt
fonte
0

Falando geralmente de encontrar arquivos por data (isso não funcionará para o pôster original, mas eu acabei aqui, então achei que outros poderiam também). No meu caso de uso, desejo listar os arquivos com a finalidade de revisá-los antes da exclusão.

Com o findutils 4.6.0, eu gosto de:

find . -type f -mtime +270 -exec ls -laFGht --time-style=iso {} \+

O comando acima localiza arquivos ( -type f), no diretório de trabalho atual ( .) que foram modificados há mais de 270 dias atrás ( -mtime +270também -mtime 0produzirá as últimas 24 horas e -mtime -5mostra os últimos 5 dias). Em seguida, ele é usado lspara listá-los por data, o mais novo primeiro ( -exec ls -laFGht --time-style=iso {} \+)

Aqui está uma amostra da saída:

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

O melhor disso é que, uma vez que a lista tenha sido revisada, é simples substituir a parte da lista pelo findcomando delete:

find . -type f -mtime +270 -delete
Steph
fonte