Ein Standardwerkzeug zum Konvertieren einer Byteanzahl in menschliches KiB-MiB usw .; wie du, ls1


94

Gibt es ein Standard-Tool , das eine Ganzzahl von Bytes in eine vom Menschen lesbare Zahl mit der größtmöglichen Einheitengröße umwandelt, während der numerische Wert zwischen 1,00 und 1023,99 liegt?

Ich habe mein eigenes Bash / Awk-Skript, suche aber ein Standard- Tool, das in vielen / den meisten Distributionen zu finden ist ... etwas allgemeineres, und idealerweise einfache Befehlszeilenargumente hat und / oder Pipe-Eingaben akzeptiert.

Hier sind einige Beispiele für die Art der Ausgabe, die ich suche.

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

Hier ist das bytes-human- Skript (wird für die obige Ausgabe verwendet)

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

Update  Hier ist eine modifizierte Version von Gilles ' Skript, wie in einem Kommentar zu seiner Antwort beschrieben.

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
Es sieht aus wie hier haben wir eine neue standard toolin der Herstellung :)
Gowtham

@ Gowtham - Ihr Wunsch kann wahr geworden sein! Siehe meine Antwort unten oder blog.frankleonhardt.com/2015/…
FJL

Beachten Sie, dass die letzten beiden Suffixe vertauscht werden. Ein Yottabyte ist tatsächlich größer als ein Zettabyte.
Staticfloat

Antworten:


89

Nein, es gibt kein solches Standardwerkzeug.

Seit GNU Coreutils 8.21 (Februar 2013, also noch nicht in allen Distributionen vorhanden) können Sie auf nicht eingebettetem Linux und Cygwin verwenden numfmt. Es wird nicht genau dasselbe Ausgabeformat erzeugt (ab Coreutils 8.23 ​​kann man meines Erachtens keine 2 Nachkommastellen erhalten).

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

Viele ältere GNU-Tools können dieses Format erzeugen und GNU-Sortierung kann Zahlen mit Einheiten seit Coreutils 7.5 sortieren (August 2009, also auf modernen, nicht eingebetteten Linux-Distributionen vorhanden).


Ich finde Ihren Code ein bisschen verworren. Hier ist eine sauberere awk-Version (das Ausgabeformat ist nicht genau identisch):

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

( Reposted von einer spezielleren Frage )


Okay danke. An deinem Drehbuch gefällt es mir im Grunde sehr gut. Es gibt ein paar Dinge, die meine Aufmerksamkeit erregt haben: (1) var ssollte führend sein B. Auch diese Zeichenfolge kann leicht in die IEC-Binärnotation geändert werden. (2) Der 1000-1023- Bereich wird zugunsten von 1 <nächste Größe> übersprungen (leicht zu ändern). (3) Es gibt keine Dezimalwerte (was ich will). Auch dies lässt sich leicht ändern. Wenn 2 Dezimalstellen angezeigt werden, %fbewirkt das Format, dass round-upfür die Werte 1019-1023 ein bis <nächste Größe> angezeigt wird . Aber es ist keine Umgehung wert. Ich habe eine modifizierte Version in meiner Antwort veröffentlicht, um allgemeine Hinweise zu geben.
Peter.O

gnumfmt für osx homebrew benutzer mit coreutils
verboze

Wenn Sie duZahlen in ein für Menschen lesbares Format konvertieren möchten , beachten Sie, dass Sie möglicherweise --block-size=1den duBefehl hinzufügen müssen .
Pawamoy

68

Ab v. 8.21, coreutilsUmfasst numfmt:

numfmtliest Zahlen in verschiedenen Darstellungen und formatiert sie wie gewünscht neu.
Die häufigste Verwendung ist die Konvertierung von Zahlen in / aus der menschlichen Darstellung.

z.B

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

Verschiedene andere Beispiele (einschließlich Filterung, Eingabe- / Ausgabeverarbeitung usw.) werden HIER vorgestellt .


Darüber hinaus, wie von coreutilsv. 8.24, numfmtKann mehrere Felder mit Feldbereich Spezifikationen ähnlich verarbeiten cut, und unterstützt die Einstellung der Ausgangspräzision mit der --formatOption ,
zB

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

numfmt ist ein neu hinzugefügtes Tool zum coreutils-Paket ab coreutils-8.21.
Zama Ques

1
Dies sollte nun die akzeptierte Antwort sein.
Andy Foster

23

Hier ist eine bcreine Bash-Option, keine oder andere nicht eingebaute Elemente, + Dezimalformat und binäre Einheiten.

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

Beispiele:

$ bytesToHuman 123456789
117.73 MiB

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

$ bytesToHuman 
0 Bytes

Sollte auf jeder Bash-Version (einschließlich MSYSGits Bash für Windows) eine gute Leistung bringen.


Dies ist die beste Antwort für meine Bash-Bedürfnisse. Leider ist es ein halbes Jahrzehnt nach dem OP-Datum veröffentlicht, was bedeutet, dass es eine Weile dauern wird, bis die Abstimmungsliste aufsteigt.
WinEunuuchs2Unix

@ WinEunuuchs2Unix danke, ich bin froh, dass es hilfreich für Sie war :)
Camilo Martin

Beachten Sie, dass die letzten beiden Suffixe vertauscht werden. Ein Yottabyte ist tatsächlich größer als ein Zettabyte.
Staticfloat

6

Dies ist eine komplette Neufassung, inspiriert von Peter.Os modifizierter Version von Gilles 'awk-Skript.

Änderungen:

  • Behebt den Fehler in Peter.O, bei dem nach einer Zeichenfolge mit> 1 Zeichen gesucht wird, bei der nach einer Zeichenfolge mit> 4 Zeichen gesucht werden soll. Aufgrund dieses Fehlers funktioniert sein Code nicht für ZiB-Einheiten.
  • Entfernt die sehr hässliche Hardcodierung einer langen Reihe von durch Leerzeichen getrennten Einheitengrößen.
  • Fügt Befehlszeilenschalter hinzu, um das Auffüllen zu aktivieren / deaktivieren.
  • Fügt Befehlszeilenschalter hinzu, um von Base-1024 (KiB) zu Base-1000 (KB) zu wechseln.
  • Wickelt alles in eine benutzerfreundliche Funktion ein.
  • Ich stelle dies in den öffentlichen Bereich und freue mich über eine breite Verwendung.

Code:

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

Testfälle (wenn Sie sich die Ausgabe ansehen möchten):

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

Genießen!


5

Es gibt ein paar perlModule im CPAN: Format :: Human :: Bytes und Number :: Bytes :: Human , wobei das letztere etwas vollständiger ist:

$ 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

Und umgekehrt:

$ 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

HINWEIS: Die Funktion parse_bytes()wurde in Version 0.09 (2013-03-01) hinzugefügt.


5

Über Linux - Gibt es einen Befehlszeilenrechner für Byte-Berechnungen? - Stapelüberlauf , ich fand über GNU-Einheiten - obwohl ohne Beispiele auf der SO-Seite; und da ich es hier nicht aufgelistet gesehen habe, ist hier eine kleine Notiz darüber.

Überprüfen Sie zunächst, ob die Einheiten vorhanden sind:

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

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

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

Wenn dies der Fall ist, führen Sie eine Konvertierung durch. printfFormatspezifizierer werden akzeptiert, um das numerische Ergebnis zu formatieren:

$ 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

Tatsächlich gibt es ein Dienstprogramm, das genau dies tut. Ich weiß, weil ich es geschrieben habe. Es wurde für * BSD geschrieben, sollte aber unter Linux kompiliert werden, wenn Sie die BSD-Bibliotheken haben (von denen ich glaube, dass sie üblich sind).

Ich habe gerade eine neue Version veröffentlicht, die hier veröffentlicht wurde:

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

Es heißt hr und nimmt stdin (oder Dateien) und konvertiert Zahlen in ein für Menschen lesbares Format, das (jetzt) ​​genau dem von ls -h usw. entspricht. Außerdem kann es einzelne Feeds in Zeilen auswählen und skalieren vorskalierte Einheiten (z. B. wenn sie in 512-Byte-Blöcken sind, konvertieren Sie sie in MB usw.), passen Sie den Spaltenabstand an und so weiter.

Ich habe es vor ein paar Jahren geschrieben, weil ich dachte, ein Shell-Skript zu schreiben, obwohl intellektuell interessant, war auch völliger Wahnsinn.

Wenn Sie beispielsweise hr verwenden, können Sie auf einfache Weise eine sortierte Liste der Verzeichnisgrößen abrufen (die in Einheiten von 1 KB ausgegeben werden und vor der Konvertierung verschoben werden müssen).

du -d1 | sort -n | hr -sK

Während du -h ausgibt, wird sort nicht danach sortiert. Das Hinzufügen von -h zu vorhandenen Dienstprogrammen ist ein klassischer Fall, bei dem die Unix-Philosophie nicht befolgt wird: Einfache Dienstprogramme erledigen definierte Aufgaben wirklich gut.


2

Hier ist eine Möglichkeit, es fast nur in Bash zu tun, benötigt nur 'bc' für die Gleitkomma-Mathematik.

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
}

Verwendungszweck:

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

Ausgabe:

   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

Gibt:

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

Leider kann ich nicht herausfinden, wie man die Genauigkeit von zwei Dezimalstellen erhält. Getestet auf Ubuntu 14.04.


1

@ don_crissti's erste Antwort ist gut, kann aber mit Here Strings noch kürzer sein , z

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

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

oder auch

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

wenn <<<nicht verfügbar, können Sie zB verwenden

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

1

Es gibt Python-Tools

$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

Ich sehe kein --binary-Flag :(, daher müsstest du Python direkt für die binäre Darstellung verwenden:

$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

Ich hatte das gleiche Problem und fand schnell eine einfache Lösung mit awkder log()Funktion:

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

Und die Genauigkeit, die bei der Verwendung von Gleitkommazahlen verloren geht, ist nicht so schlecht, da diese Genauigkeit sowieso verloren geht.


0

Die Antwort auf Ihre Frage lautet ja.

Das Ausgabeformat entspricht zwar nicht genau Ihrer Spezifikation, die Konvertierung selbst kann jedoch problemlos mit einem Standardtool (oder zwei) durchgeführt werden . Diejenigen, auf die ich mich beziehe, sind dcund bc. Sie können einen segmentierten Bericht erhalten, indem Sie die Ausgaberadices ändern. So was:

{   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

... was druckt ...

 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

Ich verwende es dcoben, weil es ein persönlicher Favorit ist, aber bcdasselbe mit unterschiedlicher Syntax tun kann und die gleichen Formatregeln einhält, wie sie von POSIX angegeben wurden, wie:

  • bc obase

    • Bei Basen größer als 16 ist jede Ziffer als separate mehrstellige Dezimalzahl zu schreiben. Vor jeder Ziffer mit Ausnahme der höchstwertigen Nachkommastelle muss ein einzelnes Leerzeichen stehen . bcSchreiben Sie für Basen von 17 bis 100 zweistellige Dezimalzahlen; Für Basen von 101 bis 1000, dreistellige Dezimalzeichenfolgen usw. Beispielsweise würde die Dezimalzahl 1024 in Basis 25 wie folgt geschrieben:

    01 15 24

    und in der Basis 125 als:

    008 024


-1

Kurz und bündig, nur Muschellösung:

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
}

Der Dezimaltrank wird nicht angezeigt.

Das let VAR=expressionist Kornisch. Ersetze VAR=$(( expression ))Born-again-ish durch.


Diese Lösung bringt eine Menge Fehler mit sich, da der / 1024 immer rundet. Ich bin sicher, dass Sie nicht 1,5 TiB auf 2 TiB aufrunden möchten.
Geoffrey

-2

AFAIK Es gibt kein solches Standardwerkzeug, an das Sie Text übergeben können, und es gibt eine für Menschen lesbare Form zurück. Möglicherweise finden Sie ein Paket, um diese Aufgabe für Ihre Distribution zu erfüllen.

Ich verstehe jedoch nicht, warum Sie ein solches Tool benötigen. Die meisten Pakete, die eine verwandte Ausgabe liefern, haben normalerweise einen Schalter -h oder einen gleichwertigen Schalter für eine lesbare Ausgabe.


1
Zum besseren Verständnis: Menschenlesbar bedeutet genau das; für den Menschen lesbar. Die verschiedenen Größeneinheiten , die von den von Ihnen erwähnten Tools angezeigt werden, sind nicht für programmatische Berechnungen vorgesehen, für die die Einheitlichkeit der Einheiten von wesentlicher Bedeutung ist. Die Arbeit mit Bytes, die immer Ganzzahlen sind, ist die einzige Möglichkeit, mit denen Bash rechnen kann. Also ... in Bytes berechnen ... in Human melden , z. "Sie sind dabei, 3 Dateien endgültig zu löschen, insgesamt 2,44 GiB. Weiter?
Peter.O

Ich denke, das sollte Teil Ihrer Frage sein. Sieht für mich so aus, als hättest du das Problem gelöst. Viel Glück.
Shellter

1
Eine übliche Anwendung besteht darin, eine Anzahl von Bytes zum Sortieren zu generieren und nach dem Sortieren in für Menschen lesbare Einheiten umzuwandeln.
Gilles
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.