килобайт для человека удобочитаемым.Ищу один лайнер - PullRequest
2 голосов
/ 21 октября 2011

Я часто работаю с коробками Unix, у которых нет флага -h для du.

Я ищу однострочник для преобразования КБ в удобочитаемый для человека. Perl казался хорошим выбором.
Это то, что я имею до сих пор.

@a=split /\s+/;
$x=$_!=0?int(log()/log(1024)):0;
@b=('K','M','G');
printf("%.3s%s\t%s\n",$_/(1024)**$x,$b[$x],$a[1]);

Беги так:

du -ks * | perl -lne '@a=split /\s+/;$x=$_!=0?int(log()/log(1024)):0;@b=('K','M','G');printf("%.3s%s\t%s\n",$_/(1024)**$x,$b[$x],$a[1]);'

Это не работает идеально, так как я не смог найти правильный формат printf.

Однострочники, использующие perl, а также awk / sed и т. Д. Были бы наиболее полезны.

Вот так выглядит du -h. Макс 1 десятичный. Мин: 0 десятичных знаков. С округлением.

8.0K
1.7M
4.0M
5.7M
88K

Обновление:

du -ks * | perl -lane '$F[0];$x=$_!=?int(log()/log(1024)):0;printf("%.3s%s\t%s\n",$_/1024**$x,qw<K M G>[$x],$F[1]);'

Ответы [ 5 ]

5 голосов
/ 21 октября 2011

Используется Number::Bytes::Human из CPAN:

du -ks * |perl -MNumber::Bytes::Human=format_bytes -nle \
    '@F=split(/\s+/,$_,2); printf("%-10s%s\n", format_bytes($F[0]*1024), $F[1])'

РЕДАКТИРОВАТЬ: без использования модулей:

du -ks * |perl -nle \
   '@F=split(/\s+/,$_,2); $b=$F[0]*1024; for($i=0;$b>1024;$i++){$b/=1024} $u=qw{B K M G T}[$i]; printf("%10.".($b=~/\./?1:0)."f$u  %s\n", $b, $F[1])'
2 голосов
/ 21 октября 2011
du -sk * | perl -ane '
  $i=0;
  while ($F[0]>1024) {$F[0]/=1024; $i++}; 
  printf("%d%s\t%s\n", $F[0], qw(K M G)[$i], $F[1])
'

Если вы хотите дроби на большие числа:

du -sk * | perl -ane '
  $i=0;
  while ($F[0]>1024) {$F[0]/=1024; $i++;};
  $f = $i==0 ? "d" : ".2f"; 
  printf("%$f%s\t%s\n", $F[0], qw(K M G)[$i], $F[1])
'
2 голосов
/ 21 октября 2011

ваш правильный формат printf ():

sub get_filesize_str
{
    my $file = shift;

    my $size = (stat($file))[7] || die "stat($file): $!\n";

    if ($size > 1099511627776) {   #   TiB: 1024 GiB
        return sprintf("%.2f TiB", $size / 1099511627776);
    } elsif ($size > 1073741824) { #   GiB: 1024 MiB
        return sprintf("%.2f GiB", $size / 1073741824);
    } elsif ($size > 1048576) {    #   MiB: 1024 KiB
        return sprintf("%.2f MiB", $size / 1048576);
    } elsif ($size > 1024) {       #   KiB: 1024 B
        return sprintf("%.2f KiB", $size / 1024);
    } else {                       #   bytes
        return sprintf("%.2f bytes", $size);
    }
}

это не мой код, он был взят из здесь

1 голос
/ 21 октября 2011

Если единственное изменение, которое вы хотите сделать (непонятно, что вы хотите), это выровнять число по правому краю в поле из 3 символов, просто удалите точку из формата printf.Кроме того, вместо явного вызова split и обработки всего $_ как числа, я бы рекомендовал передать Perl переключатель -a, который автоматически разбивает $_ на пустом месте в массив @F, а затем заменитьссылки на $_ в вашем коде с $F[0].

Таким образом, ваш код можно переписать (используя еще пару Perlisms и добавив несколько пробелов для удобства чтения) как:

du -ks * | perl -lane '$x = $F[0] != 0 && int(log($F[0])/log(1024)); printf("%3d%s\t%s\n", $F[0]/1024**$x, qw<K M G>[$x], $F[1]);'
0 голосов
/ 21 октября 2011

Вот функция AWK, адаптированная из какого-либо ответа на стеке потока:

function human_readable(sum) {

hum[1024**3]="GiB";hum[1024**2]="MiB";hum[1024]="KiB"; 
    for (x=1024**3; x>=1024; x/=1024){ 
        if (sum>=x) { v = sprintf( "%.2f %s",sum/x,hum[x]); return v }
    }
}
...