Como listar o n'ésimo arquivo mais novo (sem analisar ls!)

4

Então, eu sei que a análise ls é ruim! .

Hoje encontrei esta pepita:

FILENAME='ls -t $READ_FOLDER | head -1'

Então eu acredito que originalmente isso foi projetado para pegar o nome mais novo, agora eu quero adaptá-lo, para pegar talvez o arquivo mais novo, já que o processo que está checando é um pouco lento, e então não podemos ter certeza de que eles foram processados ainda.

Estou trabalhando no bash, mas também não sou contra uma solução genérica sh.

    
por djsmiley2k 15.09.2015 / 15:12

5 respostas

3

Você pode usar o GNU find para listar os arquivos com a hora modificada expressa como hora da época e, em seguida, usar sort para classificar a lista, finalmente head e tail para obter o nome de arquivo desejado:

find . -maxdepth 1 -type f -printf '%T@ %p\n' | sort -k1,1nr | head -5 | tail -1
    
por 15.09.2015 / 15:27
8

Perlishly:

#!/usr/bin/env perl

use strict;
use warnings;

my %files_by_mtime;

foreach my $file ( glob ( "./*" ) ) {
   my ( $mtime ) = (stat($file))[9];
   $files_by_mtime{$file} = $mtime; 
}

foreach my $f (  sort { $files_by_mtime{$b} <=> $files_by_mtime{$a} } keys %files_by_mtime ) {
   print "$f $files_by_mtime{$f}\n";
}

Reduzindo para:

perl -e '%f = map { $_ => (stat)[9] } glob("./*");print "" . ( sort { $f{$b} <=> $f{$a} } keys %f )[4];'

Onde o arquivo "N" é 4, porque os arrays perl começam do zero.

    
por 15.09.2015 / 15:46
6

Supondo que você tenha acesso às ferramentas GNU (se você estiver executando o Linux), eu usaria stat . Por exemplo:

$ ls -l
total 0
-rw-r--r-- 1 terdon terdon 0 Sep 15 16:49 file1
-rw-r--r-- 1 terdon terdon 0 Sep 15 16:39 file2
-rw-r--r-- 1 terdon terdon 0 Sep 15 16:29 file3
-rw-r--r-- 1 terdon terdon 0 Sep 15 16:19 file4
-rw-r--r-- 1 terdon terdon 0 Sep 15 16:09 file5
-rw-r--r-- 1 terdon terdon 0 Sep 15 15:59 file6
-rw-r--r-- 1 terdon terdon 0 Sep 15 15:49 file7

Portanto, o quinto arquivo mais recente é file5 . Para imprimir apenas isso, você pode fazer:

$ stat --printf '%Y %n
nthfile() {
  stat --printf '%Y %n
$ ls -l
total 0
-rw-r--r-- 1 terdon terdon 0 Sep 15 16:49 file1
-rw-r--r-- 1 terdon terdon 0 Sep 15 16:39 file2
-rw-r--r-- 1 terdon terdon 0 Sep 15 16:29 file3
-rw-r--r-- 1 terdon terdon 0 Sep 15 16:19 file4
-rw-r--r-- 1 terdon terdon 0 Sep 15 16:09 file5
-rw-r--r-- 1 terdon terdon 0 Sep 15 15:59 file6
-rw-r--r-- 1 terdon terdon 0 Sep 15 15:49 file7
' * | sort -zrnk1 | awk -vRS='
$ stat --printf '%Y %n
nthfile() {
  stat --printf '%Y %n%pre%' * | sort -zrnk1 |
     awk -vRS='%pre%' -vn="$1" 'NR==n{sub(/^[^ ]* /,"",$0); print}'
}
' * | sort -zrnk1 | awk -vRS='%pre%' 'NR==5{sub(/^[^ ]* /,"",$0); print}'
' -vn="$1" 'NR==n{sub(/^[^ ]* /,"",$0); print}' }
' * | sort -zrnk1 | awk -vRS='%pre%' 'NR==5{sub(/^[^ ]* /,"",$0); print}'

Você poderia então facilmente fazer isso em uma função de shell que pode levar N (5 no seu exemplo) como um argumento. Basta adicionar essas linhas ao seu ~/.bashrc ou equivalente:

%pre%

Observe que isso também mostrará os diretórios. Se você precisar dele para coincidir com os arquivos ocultos, bem como executar (supondo que você está usando o bash) shopt -s dotglob antes do comando acima.

Explicação

  • stat --printf '%Y %n%s' * : para cada arquivo ou diretório na pasta atual, imprima a data de modificação em segundos desde a época ( %n ) e o nome do arquivo ( \n ) e termine cada linha com sort -zrnk1 em vez de -r . Isso nos permite lidar corretamente com nomes de arquivos contendo caracteres de nova linha.
  • -z : ordena a saída na ordem inversa ( sort ), do mais recente para o mais velho. O -n indica -k1 para esperar linhas de entrada com terminação nula. O awk diz para classificar numericamente e o -vRS='vn=$1' para considerar apenas o primeiro campo ao classificar.
  • %código%:
    • n : defina o separador de registro de entrada (linha) como NR==n{} ;
    • n : defina a variável sub(/^[^ ]* /,"",$0); print para o que foi dado como entrada para a função;
    • ^[^ ]* : execute isso somente na linha %code% (5 no primeiro exemplo);
    • %code% : substitui todos os caracteres não espaciais do início da linha ( %code% ) até o primeiro espaço e imprime o resultado
por 15.09.2015 / 16:11
2

Uma maneira de fazer isso (assumindo que não há novas linhas em seus nomes de arquivo) seria

ls -t ... | head -n5 | tail -n1
    
por 15.09.2015 / 15:15
2

com zsh :

print -r -- *(.Dom[5])

fornece o quinto arquivo no diretório atual classificado por m tempo de odificação. Altere m para a para classificar por a tempo de acesso. . e D incluem apenas arquivos regulares e ocultos.

    
por 16.09.2015 / 04:41

Tags