Uno strumento standard per convertire un conteggio di byte in KiB MiB umano ecc .; come du, ls1


94

Esiste uno strumento standard che converte un conteggio intero di byte in un conteggio leggibile dall'uomo della dimensione dell'unità più grande possibile, mantenendo il valore numerico tra 1,00 e 1023,99?

Ho il mio script bash / awk, ma sto cercando uno strumento standard , che si trova su molte / la maggior parte delle distribuzioni ... qualcosa di più generalmente disponibile, e idealmente ha semplici argomenti da riga di comando, e / o posso accettare input di piping.

Ecco alcuni esempi del tipo di output che sto cercando.

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

Ecco lo script bytes-human (usato per l'output sopra)

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

Aggiorna  Ecco una versione modificata dello script di Gilles , come descritto in un commento alla sua risposta .. (modificato per adattarsi al mio aspetto preferito).

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
Sembra che qui abbiamo un nuovo standard toolin preparazione :)
Gowtham,

@Gowtham - il tuo desiderio potrebbe essere diventato realtà! Vedere la mia risposta qui sotto o blog.frankleonhardt.com/2015/...
tre strati

Si noti che gli ultimi due suffissi vengono scambiati; uno Yottabyte è in realtà più grande di uno Zettabyte.
staticfloat

Risposte:


89

No, non esiste uno strumento simile.

Da GNU coreutils 8.21 (febbraio 2013, quindi non ancora presente in tutte le distribuzioni), su Linux e Cygwin non integrati, è possibile utilizzare numfmt. Non produce esattamente lo stesso formato di output (a partire da coreutils 8.23, non credo che si possano ottenere 2 cifre dopo i punti decimali).

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

Molti vecchi strumenti GNU possono produrre questo formato e l' ordinamento GNU può ordinare i numeri con le unità da coreutils 7.5 (agosto 2009, quindi presente nelle moderne distribuzioni Linux non incorporate).


Trovo il tuo codice un po 'contorto. Ecco una versione più pulita di Awk (il formato di output non è esattamente identico):

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

( Ripubblicato da una domanda più specializzata )


Va bene, grazie. Per quanto riguarda la tua sceneggiatura, in pratica mi piace davvero. Ci sono alcune cose che hanno attirato la mia attenzione: (1) var sdovrebbe avere un ruolo guida B. Anche questa stringa può essere facilmente modificata in notazione binaria IEC. (2) Salta l' intervallo 1000-1023 a favore di 1 <dimensione successiva> (facilmente modificabile) (3) Non ha valori decimali (che desidero). Anche in questo caso è facilmente modificabile. Quando si visualizzano 2 cifre decimali, il %fformato causa round-upa <dimensione successiva> per i valori 1019-1023 ; ma non vale la soluzione alternativa. Ho pubblicato una versione modificata nella mia risposta, per riferimento generale.
Peter,

gnumfmt per gli utenti homebrew di osx che usano coreutils
verboze

Per coloro che vogliono convertire dui numeri in formato leggibile, si noti che potrebbe essere necessario aggiungere --block-size=1al ducomando.
Pawamoy,

68

A partire da v. 8.21, coreutilsInclude numfmt:

numfmtlegge i numeri in varie rappresentazioni e li riformatta come richiesto.
L'uso più comune è la conversione dei numeri in / dalla rappresentazione umana .

per esempio

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

Vari altri esempi (incluso filtraggio, elaborazione input / output ecc.) Sono presentati QUI .


Inoltre, a partire da coreutilsv. 8.24, È in numfmtgrado di elaborare più campi con specifiche di intervallo simili cute supporta l'impostazione della precisione dell'output con l' --formatopzione
ad es.

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

numfmt è uno strumento recentemente aggiunto al pacchetto coreutils da coreutils-8.21 in poi.
Zama Ques,

1
Questa dovrebbe ora essere la risposta accettata.
Andy Foster,

23

Ecco un'opzione solo bash, no bco altri non incorporati, + formato decimale e unità binarie.

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

Esempi:

$ bytesToHuman 123456789
117.73 MiB

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

$ bytesToHuman 
0 Bytes

Dovrebbe funzionare bene su qualsiasi versione di Bash disponibile (incluso Bash per Windows di MSYSGit).


Questa è la risposta migliore per le mie esigenze bash. Purtroppo è pubblicato 1/2 decennio dopo la data del PO, il che significa che ci vorrà un po 'per passare alla lista di votazione.
WinEunuuchs2Unix

@ WinEunuuchs2Unix grazie, sono contento che ti sia stato utile :)
Camilo Martin,

Si noti che gli ultimi due suffissi vengono scambiati; uno Yottabyte è in realtà più grande di uno Zettabyte.
staticfloat

6

Questa è una riscrittura completa ispirata alla versione modificata di Peter.O dello script awk di Gilles.

I cambiamenti:

  • Risolto il bug di Peter.O in cui cercava una stringa di> 1 carattere in cui avrebbe dovuto cercare uno> 4 caratteri. A causa di quel bug, il suo codice non funziona per le unità ZiB.
  • Rimuove il brutto hardcoding di una lunga serie di dimensioni di unità separate da spazio.
  • Aggiunge opzioni della riga di comando per abilitare / disabilitare il riempimento.
  • Aggiunge opzioni della riga di comando per passare dalla notazione base-1024 (KiB) alla base-1000 (KB).
  • Avvolge il tutto in una funzione facile da usare.
  • Lo metto di pubblico dominio e accolgo con favore l'uso diffuso.

Codice:

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

Casi di test (se si desidera esaminare l'output):

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

Godere!


5

Ci sono un paio di perlmoduli su CPAN: Format :: Human :: Bytes e Number :: Bytes :: Human , quest'ultimo essendo un po 'più completo:

$ 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

E il contrario:

$ 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

NOTA: la funzione è parse_bytes()stata aggiunta nella versione 0.09 (2013-03-01)


5

Via Linux - Esiste un calcolatore della riga di comando per i calcoli dei byte? - Stack Overflow , ho scoperto delle unità GNU , anche se senza esempi nella pagina SO; e poiché non l'ho visto elencato qui, ecco una piccola nota a riguardo.

Innanzitutto, controlla se le unità sono presenti:

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

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

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

Dato che lo sono, fai una conversione - gli identificatori di printfformato sono accettati per formattare il risultato numerico:

$ 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

In realtà, esiste un'utilità che fa esattamente questo. So che sono stato io a scriverlo. È stato scritto per * BSD ma dovrebbe essere compilato su Linux se hai le librerie BSD (che credo siano comuni).

Ho appena rilasciato una nuova versione, pubblicata qui:

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

Si chiama hr e prenderà stdin (o file) e convertirà i numeri in un formato leggibile dall'uomo in un modo che è (ora) esattamente uguale a ls -h e così via, e può selezionare i singoli feed in righe, ridimensionare unità pre-ridimensionate (ad es. se sono in blocchi da 512 byte convertirle in Mb ecc.), regolare il riempimento della colonna e così via.

L'ho scritto qualche anno fa perché pensavo che provare a scrivere una sceneggiatura di shell, sebbene intellettualmente interessante, fosse anche una vera follia.

Usando hr, ad esempio, puoi facilmente ottenere un elenco ordinato di dimensioni di directory (che escono in unità da 1Kb e devono essere spostate prima della conversione) con quanto segue:

du -d1 | ordina -n | h -sK

Mentre du produrrà un output -h, l'ordinamento non ordinerà in base a questo. L'aggiunta di -h ai programmi di utilità esistenti è un classico caso di non seguire la filosofia unix: avere programmi di utilità semplici che svolgono lavori definiti molto bene.


2

Ecco un modo per farlo quasi esclusivamente in bash, ha solo bisogno di 'bc' per la matematica in virgola mobile.

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
}

Uso:

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

Produzione:

   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

dà:

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

Purtroppo non riesco a capire come ottenere una precisione di due decimali. Testato su Ubuntu 14.04.


1

La prima risposta di @ don_crissti è buona, ma può essere ancora più breve usando Here Strings , ad es

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

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

o anche

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

se <<<non è disponibile è possibile utilizzare ad es

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

1

Esistono strumenti 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

Non vedo un flag --binary :(, quindi dovresti usare python direttamente per la rappresentazione binaria:

$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

Ho avuto lo stesso problema e ho trovato rapidamente una soluzione semplice usando awkla log()funzione di:

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

E la precisione persa nell'uso dei numeri float non è poi così male poiché tale precisione andrà comunque persa.


0

La risposta alla tua domanda è sì.

Sebbene il formato di output non corrisponda esattamente alle tue specifiche, la conversione stessa viene facilmente eseguita da uno (o due) strumento molto standard . Quelli a cui mi riferisco sono dce bc. Puoi ottenere un rapporto segmentato modificando i loro radices di output. Come questo:

{   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

... che stampa ...

 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

Uso dcsopra perché è un preferito personale, ma bcpuò fare lo stesso con sintassi diversa e aderisce alle stesse regole di formato specificate da POSIX come:

  • bc Obase

    • Per basi maggiori di 16, ogni cifra deve essere scritta come un numero decimale a più cifre separato. Ogni cifra ad eccezione della cifra frazionaria più significativa deve essere preceduta da un singolo spazio . Per le basi da 17 a 100, bcdevono scrivere i numeri decimali a due cifre; per basi da 101 a 1000, stringhe decimali a tre cifre e così via. Ad esempio, il numero decimale 1024 nella base 25 sarebbe scritto come:

    01 15 24

    e nella base 125, come:

    008 024


-1

Breve e dolce soluzione unica shell:

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
}

Non mostra la pozione decimale.

Il let VAR=expressionè Korn-ish. Sostituire con VAR=$(( expression ))Born-again-ish.


Questa soluzione introduce un sacco di errori poiché il / 1024 arrotonda sempre, sono sicuro che non si desidera arrotondare 1,5 TiB a 2 TiB.
Geoffrey,

-2

AFAIK non esiste uno strumento standard a cui è possibile passare il testo e restituisce un modulo leggibile dall'uomo. Potresti essere in grado di trovare un pacchetto per eseguire il suddetto compito per la tua distribuzione.

Tuttavia, non capisco perché potresti aver bisogno di un simile strumento. La maggior parte dei pacchetti che forniscono un output correlato, di solito hanno uno switch -h o equivalente per un output leggibile dall'uomo.


1
Ai fini della comprensione: leggibile dall'uomo significa proprio questo; leggibile dagli umani. Le diverse unità di dimensioni mostrate dagli strumenti citati non sono destinate ai calcoli programmatici, per i quali è essenziale l'uniformità delle unità. Lavorare con i byte, che sono sempre numeri interi, è l'unico modo in cui bash può fare qualsiasi aritmetica con essi. Quindi ... calcola in Byte ... riporta in Human , ad es. "Stai per eliminare definitivamente 3 file, per un totale di 2,44 GiB. Continua?
Peter.O

Penso che questo dovrebbe essere parte della tua domanda. Mi sembra che tu abbia risolto il problema. In bocca al lupo.
shellter,

1
Un'applicazione comune è generare numeri di byte per l'ordinamento e convertirli in unità leggibili dopo l'ordinamento.
Gilles,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.