Standardowe narzędzie do konwersji liczby bajtów na ludzką KiB MiB itp .; jak du, ls1


94

Czy istnieje standardowe narzędzie, które konwertuje liczbę całkowitą bajtów na czytelną dla człowieka liczbę największej możliwej wielkości jednostki, przy zachowaniu wartości liczbowej między 1,00 a 1023,99?

Mam swój własny skrypt bash / awk, ale szukam standardowego narzędzia, które można znaleźć w wielu / większości dystrybucji ... coś bardziej ogólnie dostępnego i idealnie ma proste argumenty wiersza poleceń i / lub może przyjąć dane potokowe.

Oto kilka przykładów rodzaju wyników, których szukam.

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

Oto skrypt bajty-człowiek (używany do powyższego wyniku)

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 ) 
   }'

Aktualizacja  Oto zmodyfikowana wersja skryptu Gillesa , opisana w komentarzu do jego odpowiedzi .. (zmodyfikowana w celu dopasowania do mojego preferowanego wyglądu).

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
Wygląda na to, że tutaj mamy nowy standard tool:)
Gowtham

@Gowtham - Twoje życzenie mogło się spełnić! Zobacz moją odpowiedź poniżej lub blog.frankleonhardt.com/2015/...
płyta

Zauważ, że dwa ostatnie sufiksy są zamienione; Yottabyte jest w rzeczywistości większy niż Zettabyte.
staticfloat

Odpowiedzi:


89

Nie, nie ma takiego standardowego narzędzia.

Ponieważ GNU coreutils 8.21 (luty 2013, więc nie jest jeszcze obecny we wszystkich dystrybucjach), w niewbudowanym systemie Linux i Cygwin możesz używać numfmt. Nie generuje dokładnie tego samego formatu wyjściowego (jak w Coreutils 8.23, nie sądzę, że można uzyskać 2 cyfry po przecinku).

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

Wiele starszych narzędzi GNU może wytwarzać ten format, a sortowanie GNU może sortować liczby za pomocą jednostek od coreutils 7.5 (sierpień 2009, więc obecne w nowoczesnych, niewbudowanych dystrybucjach Linuksa).


Twój kod jest nieco zawiły. Oto czystsza wersja awk (format wyjściowy nie jest dokładnie identyczny):

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}'

( Przesłane z bardziej specjalistycznego pytania )


Ok, dzięki. Jeśli chodzi o twój skrypt, w zasadzie bardzo go lubię. Jest kilka rzeczy, które zwróciły moją uwagę: (1) var spowinien być prowadzący B. Również ten ciąg znaków można łatwo zmienić na zapis binarny IEC. (2) Pomija zakres 1000-1023 na korzyść 1 <następny rozmiar> (łatwo zmienić) (3) Nie ma wartości dziesiętnych (których chcę). Znowu łatwo to zmienić. Podczas wyświetlania 2 miejsc po przecinku %fformat powoduje a round-updo <następnego rozmiaru> dla wartości 1019-1023 ; ale nie warto tego obejść. W mojej odpowiedzi zamieściłem zmodyfikowaną wersję w celach informacyjnych.
Peter.O

gnumfmt dla użytkowników osx homebrew korzystających z coreutils
czasownik

Jeśli chcesz przekonwertować duliczby na format czytelny dla człowieka, pamiętaj, że konieczne może być dodanie --block-size=1do dupolecenia.
pawamoy

68

Począwszy od v. 8.21, coreutilsObejmuje numfmt:

numfmtodczytuje liczby w różnych reprezentacjach i formatuje je zgodnie z żądaniem.
Najczęstszym zastosowaniem jest konwersja liczb na / z ludzkiej reprezentacji.

na przykład

printf %s\\n 5607598768908 | numfmt --to=iec-i
5,2 Ti

Różne inne przykłady (w tym filtrowanie, przetwarzanie wejścia / wyjścia itp.) Są przedstawione TUTAJ .


Ponadto, począwszy od coreutilsv. 8.24, numfmtMoże przetwarzać wiele pól ze specyfikacjami zakresu pól podobnymi cuti obsługuje ustawianie dokładności wyjściowej za pomocą --formatopcji
np.

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

numfmt to nowo dodane narzędzie do pakietu coreutils od coreutils-8.21.
Zama Ques

1
To powinna być teraz zaakceptowana odpowiedź.
Andy Foster,

23

Oto opcja tylko bash, brak bcinnych wbudowanych funkcji, format dziesiętny i jednostki binarne.

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]}"
}

Przykłady:

$ bytesToHuman 123456789
117.73 MiB

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

$ bytesToHuman 
0 Bytes

Powinien działać dobrze na dowolnej wersji Bash (w tym Bash MSYSGit dla Windows).


To najlepsza odpowiedź na moje potrzeby bash. Niestety opublikowano go 1/2 dekady po dacie OP, co oznacza, że ​​przejście do listy głosowania zajmie trochę czasu.
WinEunuuchs2Unix

@ WinEunuuchs2Unix dzięki, cieszę się, że był dla ciebie pomocny :)
Camilo Martin

Zauważ, że dwa ostatnie sufiksy są zamienione; Yottabyte jest w rzeczywistości większy niż Zettabyte.
staticfloat

6

Jest to kompletne przepisanie zainspirowane zmodyfikowaną wersją skryptu awk Gillesa autorstwa Peter.O.

Zmiany:

  • Naprawiono błąd Peter.O, w którym szuka ciągu> 1 znaku, w którym powinien szukać jednego> 4 znaków. Z powodu tego błędu jego kod nie działa dla jednostek ZiB.
  • Usuwa bardzo brzydkie kodowanie długiego łańcucha wielkości jednostek oddzielonych spacją.
  • Dodaje przełączniki wiersza poleceń, aby włączyć / wyłączyć wypełnianie.
  • Dodaje przełączniki wiersza polecenia, aby przejść z notacji base-1024 (KiB) do notacji base-1000 (KB).
  • Zawiera wszystko w łatwej w użyciu funkcji.
  • Umieszczam to w domenie publicznej i cieszę się z szerokiego zastosowania.

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 $?
}

Przypadki testowe (jeśli chcesz spojrzeć na wynik):

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}.";

Cieszyć się!


5

perlCPAN ma kilka modułów: Format :: Human :: Bytes i Number :: Bytes :: Human , ten ostatni jest nieco bardziej kompletny:

$ 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

I odwrotnie:

$ 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

UWAGA: funkcja parse_bytes()została dodana w wersji 0.09 (2013-03-01)


5

Via linux - Czy istnieje kalkulator linii poleceń do obliczeń bajtów? - Przepełnienie stosu , znalazłem informacje o jednostkach GNU - choć bez przykładów na stronie SO; a ponieważ nie widziałem go tutaj wymienionego, tutaj jest mała notka na ten temat.

Najpierw sprawdź, czy urządzenia są obecne:

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

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

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

Biorąc pod uwagę, że tak, wykonaj konwersję - printfspecyfikatory formatu są akceptowane w celu sformatowania wyniku liczbowego:

$ 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

W rzeczywistości istnieje narzędzie, które właśnie to robi. Wiem, bo to ja nie napisałem tego. Został napisany dla * BSD, ale powinien zostać skompilowany w systemie Linux, jeśli masz biblioteki BSD (które moim zdaniem są powszechne).

Właśnie wydałem nową wersję, opublikowaną tutaj:

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

Nazywa się hr i pobiera standardowe wejście (lub pliki) i konwertuje liczby na format czytelny dla człowieka w sposób, który jest (teraz) dokładnie taki sam jak ls -h itd., I może wybierać pojedyncze kanały w liniach, skalować wstępnie skalowane jednostki (np. jeśli są w blokach 512-bajtowych, konwertują je na Mb itp.), dostosuj wypełnienie kolumn i tak dalej.

Napisałem to kilka lat temu, ponieważ myślałem, że próba napisania skryptu powłoki, chociaż interesująca intelektualnie, była również kompletnym szaleństwem.

Na przykład za pomocą hr możesz łatwo uzyskać posortowaną listę rozmiarów katalogów (które wychodzą w jednostkach 1Kb i wymagają konwersji przed konwersją) w następujący sposób:

du -d1 | sort -n | hr -sK

Podczas gdy du wytworzy wyjście -h, sortowanie nie będzie sortować według niego. Dodanie -h do istniejących narzędzi to klasyczny przypadek nieprzestrzegania filozofii unixowej: proste narzędzia wykonują określone zadania naprawdę dobrze.


2

Oto sposób na zrobienie tego prawie wyłącznie w bashu, po prostu potrzebuje „bc” dla matematyki zmiennoprzecinkowej.

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
}

Stosowanie:

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

Wynik:

   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

Daje:

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

Niestety nie mogę wymyślić, jak uzyskać dokładność dwóch miejsc po przecinku. Testowane na Ubuntu 14.04.


1

Pierwsza odpowiedź @ don_crissti jest dobra, ale może być jeszcze krótsza przy użyciu Here Strings , np

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

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

lub nawet

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

jeśli <<<nie jest dostępny, możesz użyć np

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

1

Istnieją narzędzia Python

$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

Nie widzę flagi --binary :(, więc będziesz musiał użyć Pythona bezpośrednio do reprezentacji binarnej:

$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

Miałem ten sam problem i szybko wyszedł z prostego rozwiązania, używając awk„s log()funkcję:

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]
  }
'

A precyzja utracona przy użyciu liczb zmiennoprzecinkowych nie jest taka zła, ponieważ i tak zostanie utracona.


0

Odpowiedź na twoje pytanie brzmi: tak.

Chociaż format wyjściowy nie jest dokładnie zgodny ze specyfikacją, samą konwersję można łatwo wykonać za pomocą bardzo standardowego narzędzia (lub dwóch) . Te, do których się odnoszę, to dci bc. Możesz uzyskać raport podzielony na segmenty, zmieniając ich wyjściowe wartości wyjściowe. Lubię to:

{   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

... które drukuje ...

 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

Używam dcpowyżej, ponieważ jest to osobisty faworyt, ale bcmoże zrobić to samo z inną składnią i przestrzega tych samych reguł formatowania, które określono w POSIX, takich jak:

  • bc obase

    • W przypadku baz większych niż 16 każdą cyfrę zapisuje się jako oddzielną wielocyfrową liczbę dziesiętną. Każda cyfra, z wyjątkiem najbardziej znaczącej cyfry ułamkowej, poprzedzona jest pojedynczą spacją . W przypadku zasad od 17 do 100 bcnależy wpisać dwucyfrowe liczby dziesiętne; dla zasad od 101 do 1000, trzycyfrowych ciągów dziesiętnych i tak dalej. Na przykład liczba dziesiętna 1024 w podstawie 25 byłaby zapisana jako:

    01 15 24

    oraz w podstawie 125 jako:

    008 024


-1

Krótkie i słodkie rozwiązanie tylko w skorupkach:

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
}

Nie pokazuje mikstury dziesiętnej.

To let VAR=expressionjest Korn-ish. Zamień VAR=$(( expression ))na Born-again-ish.


To rozwiązanie wprowadza mnóstwo błędów, ponieważ / 1024 zawsze zaokrągla, jestem pewien, że nie chcesz zaokrąglać w górę 1,5 TiB do 2 TiB.
Geoffrey,

-2

AFAIK nie ma takiego standardowego narzędzia, do którego można przekazywać tekst, i zwraca postać czytelną dla człowieka. Być może będziesz w stanie znaleźć paczkę, aby wykonać wspomniane zadanie dla swojej dystrybucji.

Nie rozumiem jednak, dlaczego możesz potrzebować takiego narzędzia. Większość pakietów, które dają powiązane dane wyjściowe, zwykle ma przełącznik -h lub równoważny dla danych wyjściowych czytelnych dla człowieka.


1
Dla zrozumienia: „Czytelny dla człowieka” oznacza właśnie to; czytelne dla ludzi. Różne jednostki wielkości przedstawione przez wspomniane narzędzia nie są przeznaczone do obliczeń programowych, dla których niezbędna jest jednorodność jednostek. Praca z bajtami, które zawsze są liczbami całkowitymi, jest jedynym sposobem, w jaki bash może wykonywać z nimi dowolną arytmetykę. Więc ... oblicz w Bajtach ... zgłoś się do Człowieka , np. „Masz zamiar trwale usunąć 3 pliki o łącznej wartości 2,44 GiB. Kontynuować?
Peter.O

Myślę, że powinno to być częścią twojego pytania. Wygląda na to, że problem został rozwiązany. Powodzenia.
shellter

1
Typową aplikacją jest generowanie liczby bajtów do sortowania i konwersja na jednostki czytelne dla człowieka po sortowaniu.
Gilles
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.