Bir bayt sayımını insan KiB MiB'ye dönüştürmek için standart bir araç; du gibi, ls1


94

Sayısal değeri 1.00 ile 1023.99 arasında tutarken, tam sayıdaki Bayt sayısını insan tarafından okunabilen en büyük birim boyutuna dönüştüren standart bir araç var mı ?

Kendi bash / awk betiğime sahibim, ancak çoğu / çoğu dağıtımda bulunan ve daha genel olarak kullanılabilir olan ve ideal olarak basit komut satırı argümanlarına sahip ve / veya boru girişi kabul edebilen standart bir araç arıyorum .

İşte aradığım çıktı türünün bazı örnekleri.

    1    Byt  
  173.00 KiB  
   46.57 MiB  
    1.84 GiB  
   29.23 GiB  
  265.72 GiB  
    1.63 TiB  

İşte bayt-insan betiği (yukarıdaki çıktı için kullanılır)

awk -v pfix="$1" -v sfix="$2" 'BEGIN { 
      split( "Byt KiB MiB GiB TiB PiB", unit )
      uix = uct = length( unit )
      for( i=1; i<=uct; i++ ) val[i] = (2**(10*(i-1)))-1
   }{ if( int($1) == 0 ) uix = 1; else while( $1 < val[uix]+1 ) uix--
      num = $1 / (val[uix]+1)
      if( uix==1 ) n = "%5d   "; else n = "%8.2f"
      printf( "%s"n" %s%s\n", pfix, num, unit[uix], sfix ) 
   }'

Güncelleme  Burada Gilles'un senaryosunun, cevabına yaptığı bir yorumda açıklandığı gibi değiştirilmiş bir sürümüdür .. (tercihime göre görünümüme uyacak şekilde değiştirildi).

awk 'function human(x) {
         s=" B   KiB MiB GiB TiB EiB PiB YiB ZiB"
         while (x>=1024 && length(s)>1) 
               {x/=1024; s=substr(s,5)}
         s=substr(s,1,4)
         xf=(s==" B  ")?"%5d   ":"%8.2f"
         return sprintf( xf"%s\n", x, s)
      }
      {gsub(/^[0-9]+/, human($1)); print}'

4
Görünüşe göre burada yeni bir standard tool
yapımımız var

@Gowtham - dileğin gerçekleşmiş olabilir! Aşağıdaki cevabımı görün veya blog.frankleonhardt.com/2015/…
FJL

Son iki son ekin değiştirildiğine dikkat edin; Bir Yottabayt aslında bir Zettabayttan daha büyüktür.
staticfloat

Yanıtlar:


89

Hayır, böyle standart bir araç yoktur.

GNU coreutils 8.21'den (Şubat 2013, bu nedenle henüz tüm dağıtımlarda mevcut değil), gömülü olmayan Linux ve Cygwin'de kullanabilirsiniz numfmt. Tam olarak aynı çıktı biçimini üretmez (coreutils 8.23'ten itibaren, ondalık sayıdan sonra 2 basamak alabileceğinizi sanmıyorum).

$ numfmt --to=iec-i --suffix=B --padding=7 1 177152 48832200 1975684956
     1B
 173KiB
  47MiB
 1.9GiB

Birçok eski GNU aracı bu formatı üretebilir ve GNU sıralaması, çekirdekler 7.5'ten ( sayıları 2009'dan beri modern gömülü olmayan Linux dağıtımlarında mevcut olan) birimlerle birimlerle sıralayabilir .


Kodunu biraz sarsılmış buluyorum. İşte daha temiz bir awk sürümü (çıktı formatı tam olarak aynı değil):

awk '
    function human(x) {
        if (x<1000) {return x} else {x/=1024}
        s="kMGTEPZY";
        while (x>=1000 && length(s)>1)
            {x/=1024; s=substr(s,2)}
        return int(x+0.5) substr(s,1,1)
    }
    {sub(/^[0-9]+/, human($1)); print}'

( Daha uzmanlaşmış bir sorudan gönderilir )


Tamam teşekkürler. Senaryon hakkında, temelde gerçekten beğendim. Dikkatimi çeken birkaç şey var: (1) var slider olmalı B. Ayrıca bu dize kolayca IEC İkili gösterime değiştirilir. (2) 1000-1023 aralığını 1 <sonraki boyut> lehine atlar (kolayca değiştirilebilir) (3) Ondalık değerlere sahip değil (istediğim). Yine bu kolayca değiştirilebilir. 2 ondalık basamak gösterildiğinde, %fformat 1019-1023round-up değerleri için a <sonraki boyut> değerine neden olur ; ancak bu geçici bir çözüm değil. Genel referans olarak cevabımda değiştirilmiş bir sürüm yayınladım.
Peter.O

coreutils kullanarak osx homebrew kullanıcılar için gnumfmt
verboze

Dönüştürmek isteyenler için duinsanlar tarafından okunabilir formatta numaralar, eklemek gerekebilir unutmayın --block-size=1için dukomuta.
pawamoy

68

V. İtibariyle 8.21, coreutilsşunları içerir numfmt:

numfmtÇeşitli temsillerde sayıları okur ve istendiği gibi yeniden biçimlendirir.
En yaygın kullanım, sayıları insan temsilinden / temsiline dönüştürmektir .

Örneğin

printf %s\\n 5607598768908 | numfmt --to=iec-i
5.2Ti

BURADA çeşitli başka örnekler (filtreleme, giriş / çıkış işlemleri vb . Dahil) sunulmuştur .


Buna ek olarak, itibariyle coreutilsv. 8.24, numfmtBenzer alan aralığı özellikleriyle birden çok alan işleyebilir cutve birlikte çıkış hassasiyet ayarı destekler --formatseçenek
ör

numfmt --to=iec-i --field=2,4 --format='%.3f' <<<'tx: 180000 rx: 2000000'
tx: 175.782Ki rx: 1.908Mi

numfmt, coreutils-8.21'den itibaren coreutils paketine yeni eklenen bir araçtır.
Zama

1
Bu şimdi kabul edilen cevap olmalıdır.
Andy Foster

23

İşte sadece bash seçeneği, hiçbir bcyerleşik olmayan başka bir seçenek , + ondalık format ve ikili birimler.

bytesToHuman() {
    b=${1:-0}; d=''; s=0; S=(Bytes {K,M,G,T,P,E,Z,Y}iB)
    while ((b > 1024)); do
        d="$(printf ".%02d" $((b % 1024 * 100 / 1024)))"
        b=$((b / 1024))
        let s++
    done
    echo "$b$d ${S[$s]}"
}

Örnekler:

$ bytesToHuman 123456789
117.73 MiB

$ bytesToHuman 1000000000000 # "1TB of storage"
931.32 GiB                   #  1TB of storage

$ bytesToHuman 
0 Bytes

Dışarıdaki Bash sürümünde iyi performans göstermelidir (MSYSGit'in Windows için Bash'i de dahil).


Bu benim bash ihtiyaçlarım için en iyi cevap. Maalesef, OP tarihinden sonra 10 yıl boyunca 1/2 oy verildi, oylama listesinin yükselmesi biraz zaman alacak.
WinEunuuchs2Unix

@ WinEunuuchs2Unix teşekkürler, size yardımcı oldu sevindim :)
Camilo Martin

Son iki son ekin değiştirildiğine dikkat edin; Bir Yottabayt aslında bir Zettabayttan daha büyüktür.
staticfloat

6

Bu Peter.O'nun Gilles 'awk betiğinin değiştirilmiş versiyonundan ilham alan tam bir yeniden yazma.

değişiklikler:

  • Peter.O'nun bir> 4 karakter araması gereken> 1 karakterden oluşan bir dize aradığı hatayı düzeltir. Bu hata nedeniyle, kodu ZiB birimleri için çalışmıyor.
  • Uzun boşlukla ayrılmış birim boyutlarının çok çirkin sabit kodlamasını kaldırır.
  • Dolguyu etkinleştirmek / devre dışı bırakmak için komut satırı anahtarları ekler.
  • Base-1024'ten (KiB) base-1000 (KB) notasyonuna geçmek için komut satırı anahtarları ekler.
  • Kullanımı kolay bir işlevle hepsini sarar.
  • Bunu kamuya açık bir şekilde yapıyorum ve yaygın şekilde kullanılmasına izin veriyorum.

Kod:

bytestohuman() {
    # converts a byte count to a human readable format in IEC binary notation (base-1024), rounded to two decimal places for anything larger than a byte. switchable to padded format and base-1000 if desired.
    local L_BYTES="${1:-0}"
    local L_PAD="${2:-no}"
    local L_BASE="${3:-1024}"
    BYTESTOHUMAN_RESULT=$(awk -v bytes="${L_BYTES}" -v pad="${L_PAD}" -v base="${L_BASE}" 'function human(x, pad, base) {
         if(base!=1024)base=1000
         basesuf=(base==1024)?"iB":"B"

         s="BKMGTEPYZ"
         while (x>=base && length(s)>1)
               {x/=base; s=substr(s,2)}
         s=substr(s,1,1)

         xf=(pad=="yes") ? ((s=="B")?"%5d   ":"%8.2f") : ((s=="B")?"%d":"%.2f")
         s=(s!="B") ? (s basesuf) : ((pad=="no") ? s : ((basesuf=="iB")?(s "  "):(s " ")))

         return sprintf( (xf " %s\n"), x, s)
      }
      BEGIN{print human(bytes, pad, base)}')
    return $?
}

Test Durumları (çıktıya bakmak istiyorsanız):

bytestohuman 1; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 500; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 1023; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 1024; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 1500; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000000000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000000000000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000000000000000; echo "${BYTESTOHUMAN_RESULT}.";

bytestohuman 1 no 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 500 no 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 1023 no 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 1024 no 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 1500 no 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000 no 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000 no 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000000 no 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000000000 no 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000000000000 no 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000000000000000 no 1000; echo "${BYTESTOHUMAN_RESULT}.";

bytestohuman 1 yes; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 500 yes; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 1023 yes; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 1024 yes; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 1500 yes; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000 yes; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000 yes; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000000 yes; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000000000 yes; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000000000000 yes; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000000000000000 yes; echo "${BYTESTOHUMAN_RESULT}.";

bytestohuman 1 yes 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 500 yes 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 1023 yes 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 1024 yes 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 1500 yes 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000 yes 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000 yes 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000000 yes 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000000000 yes 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000000000000 yes 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000000000000000 yes 1000; echo "${BYTESTOHUMAN_RESULT}.";

Keyfini çıkarın!


5

perlCPAN'da birkaç modül var: Format :: İnsan :: Bayt ve Sayı :: Bayt :: İnsan , ikincisi biraz daha tamamlandı:

$ echo 100 1000 100000 100000000 |
  perl -M'Number::Bytes::Human format_bytes' -pe 's/\d{3,}/format_bytes($&)/ge'
100 1000 98K 96M

$ echo 100 1000 100000 100000000 |
  perl -M'Number::Bytes::Human format_bytes' -pe 's/\d{3,}/
   format_bytes($&,bs=>1000, round_style => 'round', precision => 2)/ge'
100 1.00k 100k 100M

Ve tam tersi:

$ echo 100 1.00k 100K 100M 1Z |
  perl -M'Number::Bytes::Human parse_bytes' -pe '
    s/[\d.]+[kKMGTPEZY]/parse_bytes($&)/ge'
100 1024 102400 104857600 1.18059162071741e+21

NOT: Fonksiyon parse_bytes()edildi sürümü 0.09 eklenen (2013/03/01)


5

Via linux - bayt hesaplamaları için bir komut satırı hesap makinesi var mı? - Yığın Taşması , GNU Üniteleri hakkında buldum - SO sayfasında örnekler olmasa da; ve burada listelenen görmedim, burada küçük bir not.

İlk olarak, birimlerin mevcut olup olmadığını kontrol edin:

$ units --check-verbose |grep byte
doing 'byte'

$ units --check-verbose |grep mega
doing 'megalerg'
doing 'mega'

$ units --check-verbose |grep mebi
doing 'mebi'

Oldukları göz önüne alındığında, bir dönüştürme printfbiçimi tanımlayıcıları sayısal sonucu biçimlendirmek için kabul edilir:

$ units --one-line -o "%.15g" '20023450 bytes' 'megabytes'  # also --terse
    * 20.02345
$ units --one-line -o "%.15g" '20023450 bytes' 'mebibytes' 
    * 19.0958499908447
$ units --one-line -o "%.5g" '20023450 bytes' 'mebibytes' 
    * 19.096

3

Aslında, tam olarak bunu yapan bir yardımcı program var. Biliyorum çünkü ben yazmıştım. * BSD için yazılmıştır, ancak eğer BSD kütüphanelerine sahipseniz Linux'ta derlemeliyim (ki bunlar ortak).

Yeni bir sürüm yayınladım, burada yayınlanan:

http://blog.frankleonhardt.com/2015/freebsd-hr-utility-human-readable-number-filter-man-page/

Bu, hr olarak adlandırılır ve stdin (veya dosyaları) alır ve sayıları insan tarafından okunabilir formata dönüştürür (şimdi) tam olarak ls -h ile aynı şekilde olur ve satırlar halinde ayrı beslemeleri seçebilir, ölçeklendirir önceden ölçeklendirilmiş birimler (örneğin 512 bayt bloklardaysa, bunları Mb'ye dönüştürürler), sütun dolgusunu ayarlayın, vb.

Birkaç yıl önce yazdım, çünkü entelektüel olarak ilginç olsa da tam bir delilik olduğunu düşündüğüm bir kabuk senaryosu yazmaya çalışıyordum.

Örneğin, hr kullanarak, aşağıdakilerle kolayca dizilmiş bir dizin listesi (1Kb birimde çıkan ve dönüştürmeden önce kaydırılması gerekir) alabilirsiniz:

du-d1 | sıralama -n | hr -sK

Du -h çıktı üretecek olsa da, sıralama buna göre sıralamaz. -H'nin mevcut hizmetlere eklenmesi, unix felsefesini izlememek için klasik bir durumdur: tanımlanmış işleri gerçekten iyi yapan basit hizmetlere sahip olmak.


2

İşte neredeyse tamamen bash yapmanın bir yolu, sadece kayan nokta matematiği için 'bc'ye ihtiyaç var.

function bytesToHR() {
        local SIZE=$1
        local UNITS="B KiB MiB GiB TiB PiB"
        for F in $UNITS; do
                local UNIT=$F
                test ${SIZE%.*} -lt 1024 && break;
                SIZE=$(echo "$SIZE / 1024" | bc -l)
        done

    if [ "$UNIT" == "B" ]; then
        printf "%4.0f    %s\n" $SIZE $UNIT
    else
        printf "%7.02f %s\n" $SIZE $UNIT
    fi
}

Kullanımı:

bytesToHR 1
bytesToHR 1023
bytesToHR 1024
bytesToHR 12345
bytesToHR 123456
bytesToHR 1234567
bytesToHR 12345678

Çıktı:

   1    B
1023    B
   1.00 KiB
  12.06 KiB
 120.56 KiB
   1.18 MiB
  11.77 MiB

1
user@host:/usr$ alias duh="du -s -B1 * | sort -g | numfmt --to=iec-i --format='%10f'"
user@host:/usr$ duh

verir:

 4.0Ki games
 3.9Mi local
  18Mi include
  20Mi sbin
 145Mi bin
 215Mi share
 325Mi src
 538Mi lib

Ne yazık ki, iki ondalık doğruluğun nasıl elde edileceğini bulamıyorum. Ubuntu 14.04'te test edilmiştir.


1

@ don_crissti'nin ilk Yanıtı iyi, ancak Here Strings kullanarak daha kısa olabilir , örn.

$ numfmt --to=iec-i <<< "12345"
13Ki

$ numfmt --to=iec-i --suffix=B <<< "1234567"
1.2MiB

ya da

$ numfmt --from=iec-i --to=iec-i --suffix=B <<< "12345Ki"
13MiB

<<<mevcut değilse , örneğin

$ echo "1234567" | numfmt --to=iec-i --suffix=B
1.2MiB

1

Python araçları var

$pip install humanfriendly  # Also available as a --user install in ~/.local/bin

$humanfriendly --format-size=2048
2.05 KB
$humanfriendly --format-number=2048
2,048

--Binary flag :( göremiyorum, bu yüzden python'u ikili gösterim için doğrudan kullanmanız gerekir:

$python -c 'import sys, humanfriendly; print(humanfriendly.format_size(int(sys.argv[1]), binary=True))' 2048
2 KiB
$python -c 'import sys, humanfriendly; print(humanfriendly.format_size(int(sys.argv[1]), binary=True))' 2000
1.95 KiB

1

Aynı problemi yaşadım ve çabucak awk' log()fonksiyonunu kullanarak basit bir çözüm buldum :

awk '
  BEGIN {
    split("B,kiB,MiB,GiB", suff, ",")
  }

  {
    size=$1;
    rank=int(log(size)/log(1024));
    printf "%.4g%s\n", size/(1024**rank), suff[rank+1]
  }
'

Şamandıra sayılarını kullanırken kaybedilen hassasiyet o kadar da kötü değil çünkü bu hassasiyet yine de kaybedilecek.


0

Sorunuzun cevabı evet.

Çıktı formatı tam olarak sizin spesifikasyonunuza uygun olmasa da, dönüşümün kendisi çok standart bir araçla (ya da iki) kolayca yapılır . Başvurduğumlar dcve bc. Çıktı yarıçaplarını değiştirerek bölümlere ayrılmış bir rapor alabilirsiniz. Bunun gibi, böyle:

{   echo 1024 o           #set dc's output radix
    echo 1023 pc          #echo a number then print + clear commands
    echo 1024 pc
    echo 1025 pc
    echo 8000000 pc
} | dc

... hangi baskılar ...

 1023                    #1 field 1023 bytes
 0001 0000               #2 fields 1k 0b
 0001 0001               #2 fields 1k 1b
 0007 0644 0512          #3 fields 7m 644k 512b or 7.64m

Kullandığım dcbir kişisel favori olduğunu, ancak çünkü yukarıda bcfarklı sözdizimi ile aynısını yapabilir ve benzeri POSIX tarafından belirlenen aynı biçim kurallara uyar:

  • bc obase

    • 16'dan büyük tabanlar için, her bir basamak ayrı bir çok basamaklı ondalık sayı olarak yazılmalıdır. En önemli kesir basamağı dışındaki her rakam bir boşluktan önce gelecektir . 17'den 100'e kadar olan tabanlar için bciki basamaklı ondalık sayılar yazacaktır; 101'den 1000'e kadar olan tabanlar için, üç basamaklı ondalık basamaklar vb. Örneğin, 25 tabanındaki 1024 ondalık sayı şöyle yazılır:

    01 15 24

    ve baz 125’de:

    008 024


-1

Kısa ve tatlı, kabuk sadece çözüm:

convertB_human() {
NUMBER=$1
for DESIG in Bytes KB MB GB TB PB
do
   [ $NUMBER -lt 1024 ] && break
   let NUMBER=$NUMBER/1024
done
printf "%d %s\n" $NUMBER $DESIG
}

Ondalık iksirini göstermiyor.

let VAR=expressionKorn-ish. İle değiştirin VAR=$(( expression ))Born-tekrar-imsi için.


Bu çözüm, / 1024 her zaman yuvarlandığı için bir ton hata veriyor, 1,5 TiB ila 2 TiB toplamak istemediğinizden eminim.
Geoffrey

-2

AFAIK, metin iletebileceğiniz standart bir araç yoktur ve insan tarafından okunabilir bir form döndürür. Dağıtımınız için söz konusu görevi gerçekleştirmek için bir paket bulabilirsiniz.

Ancak, neden böyle bir araca ihtiyacınız olabileceğini anlamıyorum. İlgili bir çıktı veren çoğu paket, genellikle insan tarafından okunabilir çıktı için -h ya da eşdeğer bir anahtara sahiptir.


1
Anlama amaçları için: İnsan tarafından okunabilir, tam da bunun anlamına gelir; insanlar tarafından okunabilir. Bahsettiğiniz araçların gösterdiği farklı büyüklükteki birimler, birimlerin tek biçimliliğinin gerekli olduğu programlı hesaplamalar için tasarlanmamıştır. Her zaman tam sayı olan baytlarla çalışmak, bash'ın bunlarla herhangi bir aritmetik yapabilmesi için tek yoldur . Yani ... lütfen hesaplamak Bayt 'de ... raporunda İnsan örn. "Toplam 2,44 GiB tutarında 3 dosyayı kalıcı olarak silmek
üzeresiniz

Bence bu sorunuzun bir parçası olmalı. Bana problemi çözmüş gibisin. İyi şanslar.
shellter

1
Yaygın bir uygulama, sıralama için bayt sayıları oluşturmak ve sıralamadan sonra insan tarafından okunabilen birimlere dönüştürmektir.
Gilles
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.