Isso funciona (atualizado para incorporar a sugestão de Daniel Andersson):
find -type f -printf '%T+ %p\n' | sort | head -n 1
Eu estou procurando por um shell one-liner para encontrar o arquivo mais antigo em uma árvore de diretórios.
Este é um pouco mais portátil e porque não depende do GNU find
extension -printf
, então também funciona no BSD / OS X:
find . -type f -print0 | xargs -0 ls -ltr | head -n 1
A única desvantagem aqui é que é um pouco limitada ao tamanho de ARG_MAX
(que deve ser irrelevante para a maioria dos novos kernels). Então, se houver mais de getconf ARG_MAX
caracteres retornados (262.144 no meu sistema), isso não lhe dará o resultado correto. Também não é compatível com POSIX porque -print0
e xargs -0
não são.
Mais algumas soluções para esse problema estão descritas aqui: Como posso encontrar o arquivo mais recente (mais antigo, mais antigo) em um diretório ? - Wiki de Greg
Os seguintes comandos de comando têm a garantia de funcionar com qualquer tipo de nome de arquivo estranho:
find -type f -printf "%T+ %pfind -type f -printf "%T+ %p%pre%" | sort -z | grep -zom 1 ".*" | cat
find -type f -printf "%T@ %T+ %p%pre%" | \
sort -nz | grep -zom 1 ".*" | sed 's/[^ ]* //'
stat -c "%y %n" "$(find -type f -printf "%T@ %p%pre%" | \
sort -nz | grep -zom 1 ".*" | sed 's/[^ ]* //')"
" | sort -z | grep -zom 1 ".*" | cat
find -type f -printf "%T@ %T+ %p%pre%" | \
sort -nz | grep -zom 1 ".*" | sed 's/[^ ]* //'
stat -c "%y %n" "$(find -type f -printf "%T@ %p%pre%" | \
sort -nz | grep -zom 1 ".*" | sed 's/[^ ]* //')"
Usar um byte nulo (
) em vez de um caractere de alimentação de linha ( \n
-z
) garante que a saída de localização ainda seja compreensível caso um dos nomes de arquivo contenha um caractere de alimentação de linha.
A opção grep -m 1
faz a classificação e o grep interpretarem somente bytes nulos como caracteres de fim-de-linha. Como não há esse tipo de mudança, usamos sort -n
(apenas uma ocorrência).
Os comandos são ordenados por tempo de execução (medido na minha máquina).
O primeiro comando será o mais lento, já que ele deve converter primeiro o arquivo mtime de cada arquivo em um formato legível por humanos e depois ordená-los. Piping to cat evita colorir a saída.
O segundo comando é um pouco mais rápido. Enquanto ele ainda realiza a conversão de data, numericamente ( %code% ) os segundos decorridos desde a época do Unix são um pouco mais rápidos. sed apaga os segundos desde a época do Unix.
O último comando não faz nenhuma conversão e deve ser significativamente mais rápido que os dois primeiros. O comando find em si não exibirá o mtime do arquivo mais antigo, portanto, stat é necessário.
Páginas de manual relacionadas: find - grep - sed - classificar - stat
Embora a resposta aceita e outras pessoas façam o trabalho, se você tiver uma árvore muito grande, todas elas ordenarão todo o conjunto de arquivos.
Melhor seria se pudéssemos apenas listá-los e rastrear os mais antigos, sem a necessidade de classificar nada.
Foi por isso que surgiu esta solução alternativa:
ls -lRU $PWD/* | awk 'BEGIN {cont=0; oldd=strftime("%Y%m%d"); } { gsub(/-/,"",$6); if (substr($1,0,1)=="/") { pat=substr($1,0,length($0)-1)"/"; }; if( $6 != "") {if ( $6 < oldd ) { oldd=$6; oldf=pat$8; }; print $6, pat$8; count++;}} END { print "Oldest date: ", oldd, "\nFile:", oldf, "\nTotal compared: ", count}'
Espero que possa ser de alguma ajuda, mesmo que a pergunta seja um pouco antiga.
Editar 1: essas alterações permitem analisar arquivos e diretórios com espaços. É rápido o suficiente para emiti-lo na raiz /
e encontrar o arquivo mais antigo de sempre.
ls -lRU --time-style=long-iso "$PWD"/* | awk 'BEGIN {cont=0; oldd=strftime("%Y%m%d"); } { gsub(/-/,"",$6); if (substr($0,0,1)=="/") { pat=substr($0,0,length($0)-1)"/"; $6="" }; if( $6 ~ /^[0-9]+$/) {if ( $6 < oldd ) { oldd=$6; oldf=$8; for(i=9; i<=NF; i++) oldf=oldf $i; oldf=pat oldf; }; count++;}} END { print "Oldest date: ", oldd, "\nFile:", oldf, "\nTotal compared: ", count}'
Comando explicado:
Executando:
~$time ls -lRU "$PWD"/* | awk etc.
Oldest date: 19691231
File: /home/.../.../backupold/.../EXAMPLES/how-to-program.txt
Total compared: 111438
real 0m1.135s
user 0m0.872s
sys 0m0.760s
EDIT 2: Mesmo conceito, melhor solução usando find
para ver o tempo de acesso (use %T
com o primeiro printf
para tempo de modificação ou %C
para mudança de status ).
find . -wholename "*" -type f -printf "%AY%Am%Ad %h/%f\n" | awk 'BEGIN {cont=0; oldd=strftime("%Y%m%d"); } { if ($1 < oldd) { oldd=$1; oldf=$2; for(i=3; i<=NF; i++) oldf=oldf " " $i; }; count++; } END { print "Oldest date: ", oldd, "\nFile:", oldf, "\nTotal compared: ", count}'
EDIT 3: O comando abaixo usa tempo de modificação e também imprime progresso incremental conforme encontra arquivos antigos e antigos, o que é útil quando você tem alguns timestamps incorretos (como 1970-01-01):
find . -wholename "*" -type f -printf "%TY%Tm%Td %h/%f\n" | awk 'BEGIN {cont=0; oldd=strftime("%Y%m%d"); } { if ($1 < oldd) { oldd=$1; oldf=$2; for(i=3; i<=NF; i++) oldf=oldf " " $i; print oldd " " oldf; }; count++; } END { print "Oldest date: ", oldd, "\nFile:", oldf, "\nTotal compared: ", count}'
Por favor, use ls - a página man informa como encomendar o diretório.
ls -clt | head -n 2
O -n 2 é para que você não obtenha o "total" na saída. Se você quer apenas o nome do arquivo.
ls -t | head -n 1
E se você precisar da lista na ordem normal (obtendo o arquivo mais novo)
ls -tr | head -n 1
Muito mais fácil do que usar o find, muito mais rápido e mais robusto - não precisa se preocupar com formatos de nomenclatura de arquivos. Deve funcionar em quase todos os sistemas também.
find ! -type d -printf "%T@ %p\n" | sort -n | head -n1
Parece que por "mais antigos" a maioria das pessoas assumiu que você queria dizer "tempo de modificação mais antigo". Isso é provavelmente corrigido, de acordo com a interpretação mais rigorosa de "mais antigo", mas no caso de você querer aquele com o tempo de acesso mais antigo , eu modificaria a melhor resposta assim:
find -type f -printf '%A+ %p\n' | sort | head -n 1
Observe o %A+
.
set $(find /search/dirname -type f -printf '%T+ %h/%f\n' | sort | head -n 1) && echo $2
find ./search/dirname -type f -printf '%T+ %h/%f\n'
imprime datas e nomes de arquivos em duas colunas. sort | head -n1
mantém a linha correspondente ao arquivo mais antigo. echo $2
exibe a segunda coluna, ou seja, o nome do arquivo.