Necesito averiguar qué directorios en un árbol tienen más archivos (pero no en sus subdirectorios). Los directorios no deben contarse.

Esto es fácilmente soluble con bash, Perl, Python, Tcl, etc. pero es interesante resolverlo de una sola vez.

Escribí el siguiente one-liner que cuenta correctamente

ls -Rp1 | grep -vP '\/$' | perl -pe 's/\n/ /' | perl -e '$ln=<>;@ds=split/(?=\.\/)/,$ln;for(@ds){($d,$fs)=split/:/;$fs=~s/^\s+|\s+$//;$c=split/\s+/,$fs;$fc+=$c;print "$c $d\n"}print "Totals: dirs: @{[scalar @ds]}, files: $fc\n"' | sort -n

¿Existe una solución de una línea más elegante para hacer esto, no necesariamente con Perl?

Este es el equivalente de varias líneas

#!/usr/bin/perl

$line = <>;
@dirs = split/(?=\.\/)/, $line;

for ( @dirs ) {
    ($dir, $files) = split /:/;
    $files =~ s/^\s+|\s+$//;
    $count = split/\s+/, $files;
    $total_files_count += $count;
    print "$count $dir\n"
}

print "Totals: dirs: @{[scalar @dirs]}, files: $total_files_count\n";
0
a1111exe 20 oct. 2017 a las 18:56

3 respuestas

La mejor respuesta

¿No funcionaría esto?

find . -type f | sed -e 's/[^\\/]*$//' | sort | uniq -c | sort -rn | head -10

PD: es posible que desee publicar el desafío de codificar golf si la intención es el código más corto.

2
jcaron 20 oct. 2017 a las 16:58

Algo como esto funcionará:

#!/usr/bin/perl

use strict;
use warnings;

countFiles($ARGV[0]);

sub countFiles() {
        my $dir=shift;
        my @list=glob("$dir/*");
        my $count=0;
        for (@list) {
                if (-d) {
                        countFiles($_);
                }
                else {
                        $count++;
                }
        }
        print "directory=$dir, file count=$count\n";
}

O un trazador de líneas

find . -type f | perl -e 'while(<ARGV>){chomp;s/(.*\/).*$/\1/; $hash{$_}++;}for(keys %hash){print "$_ count=$hash{$_}\n";}'
1
Essex Boy 20 oct. 2017 a las 16:31

Un forro "uno" de Perl, que utiliza núcleo (y eficiente) Archivo :: Buscar

perl -MFile::Find -wE'
    find({no_chdir=>1, wanted => sub { ++$dc{$File::Find::dir} if -f }}, "."); 
    printf "%4d => $_\n", $dc{$_} for sort { $dc{$b} <=> $dc{$a} } keys %dc;
'

Impresión de recuentos (correctos) de archivos "normales" (-f) en cada directorio (y no en sus subdirectorios)

  45 => .
   7 => ./dir/sub_dir_1
   4 => ./dir
   3 => ./another_dir
   2 => ./dir/sub_dir_2

O con Archivo :: Buscar: : Regla que tiene una interfaz más agradable y con un formato de salida diferente

perl -MList::Util=max -MFile::Find::Rule -wE'
    @dirs   = File::Find::Rule->directory->in(".");
    $dc{$_} = File::Find::Rule->file->maxdepth(1)->in($_) for @dirs;
    @skeys = sort { $dc{$b} <=> $dc{$a} } keys %dc;
    $ml = max map { length } @skeys; 
    for (@skeys) { printf "%${ml}s => $dc{$_}\n", $_ }
'

Las últimas tres líneas y -MList::Util=max solo están allí para el formato de salida. Huellas dactilares

            . => 47
dir/sub_dir_1 => 7
          dir => 4
  another_dir => 3
dir/sub_dir_2 => 2
    empty_dir => 0

1
zdim 26 oct. 2017 a las 07:26