it-swarm-eu.dev

Standardní nástroj pro převod počtu bytů na lidský KiB MiB atd .; jako du, ls1

Existuje standardní nástroj, který převádí celé číslo bajtů na počet čitelný pro člověka s největší možnou velikostí jednotky při zachování numerické hodnoty mezi 1,00 a 1023,99?

Mám svůj vlastní bash/awk skript, ale hledám standardní nástroj, který se nachází na mnoha/nejvíce distrosech ... něco obecně dostupnějšího a ideálně má jednoduché příkazové řádky a/nebo může přijmout potrubí.

Zde je několik příkladů typu výstupu, který hledám.

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

Zde je skript bytes-human (použitý pro výše uvedený výstup)

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

Aktualizace Zde je upravená verze skriptu Gilles ', jak je popsáno v komentáři k jeho odpovědi .. (upraveno tak, aby vyhovovalo mému preferovanému vzhledu).

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}'
106
Peter.O

Ne, takový standardní nástroj neexistuje.

Vzhledem k tomu, že GNU coreutils 8.21 (únor 2013, dosud není přítomen ve všech distribucích), můžete na Linuxu a Cygwin, který není vložen, použít numfmt . Nevytváří přesně stejný výstupní formát (jako u Coreutils 8.23, nemyslím si, že můžete získat 2 číslice za desetinnými místy).

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

Mnoho starších GNU nástrojů může tento formát produkovat a GNU třídění umí třídit čísla podle jednotek od coreutils 7.5 (srpen 2009, tedy přítomných na moderních neintegrovaných distribucích Linuxu).


Zjistil jsem, že váš kód je trochu spletitý. Zde je čistší verze awk (výstupní formát není úplně totožný):

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

( Odděleno od specializovanější otázky )

Od v. 8.21, coreutils zahrnuje numfmt :

numfmt čte čísla v různých reprezentacích a přeformátuje je podle potřeby.
Nejběžnější použití je převod čísel na/z lidské reprezentace.

např.

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

Různé další příklady (včetně filtrování, zpracování vstupů/výstupů atd.) Jsou uvedeny ZDE .


Navíc od coreutils v. 8.24, numfmt může zpracovávat více polí se specifikacemi rozsahu pole podobnými cut a podporuje nastavení přesnosti výstupu pomocí --format možnost
např.

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

Zde je možnost pouze pro bash, žádné bc nebo jiné nestavěné + desítkový formát a binární jednotky.

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

Příklady:

$ bytesToHuman 123456789
117.73 MiB

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

$ bytesToHuman 
0 Bytes

Měl by dobře fungovat na jakékoli verzi Bash tam (včetně MSYSGit's Bash pro Windows).

29
Camilo Martin

Přes linux - Existuje kalkulačka příkazového řádku pro bajtové výpočty? - Stack Overflow , našel jsem asi GNU Units - i když bez příkladů na stránce SO; a protože jsem to zde neviděl, je tu malá poznámka.

Nejprve zkontrolujte, zda jsou jednotky přítomny:

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

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

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

Vzhledem k tomu, že jsou, proveďte převod - pro formátování číselného výsledku jsou přijaty specifikátory formátu printf:

$ 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
7
sdaau

Toto je kompletní přepis inspirovaný upravenou verzí Petera Oka awk skriptu.

Změny:

  • Opravuje chybu Peter.O, kde hledá řetězec> 1 znak, kde by měl hledat jeden> 4 znaky. Kvůli této chybě nefunguje jeho kód pro jednotky ZiB.
  • Odstraňuje velmi ošklivé zakódování dlouhého řetězce velikostí jednotek oddělených prostorem.
  • Přidá přepínače příkazového řádku k povolení nebo zakázání čalounění.
  • Přidá přepínače příkazového řádku a přejde z notace base-1024 (KiB) do notace base-1000 (KB).
  • Zabalí to do snadno použitelné funkce.
  • Umístím to na veřejnou doménu a vítám široké použití.

Kód:

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

Testovací případy (pokud se chcete podívat na výstup):

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

Užívat si!

6
John

Na CPAN existuje několik modulů Perl: Format :: Human :: Bajty a Number :: Bajty :: Human , přičemž poslední je trochu úplnější:

$ 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

A naopak:

$ 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

POZNÁMKA: funkce parse_bytes() byla přidáno ve verzi 0.09 (2013-03-01)

5

Ve skutečnosti existuje nástroj, který to přesně dělá. Vím, protože jsem to napsal já. Byl vytvořen pro * BSD, ale měl by se kompilovat na Linuxu, pokud máte knihovny BSD (které jsou podle mě běžné).

Právě jsem vydal novou verzi, zveřejněnou zde:

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

Říká se tomu hr a bude to trvat stdin (nebo soubory) a převádí čísla do formátu čitelného člověkem způsobem, který je (nyní) přesně stejný jako ls-h atd., A může vybrat jednotlivé kanály v řádcích, měřítku předem upravené jednotky (např. pokud jsou v blocích 512 bajtů převedeny na Mb atd.), upravte výplň sloupců atd.

Napsal jsem to před několika lety, protože jsem si myslel, že pokus o psaní skriptu Shell, i když intelektuálně zajímavý, byl také naprosté šílenství.

Například pomocí hr můžete snadno získat seřazený seznam velikostí adresářů (které vyjdou v jednotkách 1 kB a před převodem je třeba je převést) s následujícím:

du-d1 | sort -n | hr-sK

Zatímco du bude produkovat -h výstup, řazení se nebude třídit. Přidání parametru -h ke stávajícím nástrojům je klasický případ nedodržování unixové filozofie: mají jednoduché nástroje, které opravdu dobře definují definované úlohy.

3
FJL

Tady je způsob, jak to udělat téměř čistě v bash, pro matematiku s plovoucí desetinnou čárkou stačí „bc“.

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
}

Používání:

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

Výstup:

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

Měl jsem stejný problém a rychle jsem přišel s jednoduchým řešením pomocí funkce awklog():

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 přesnost ztracená při používání float čísel není tak špatná, protože ta přesnost bude stejně ztracena.

2
Bence Kiglics

První odpověď @ don_crissti je dobrá, ale může být ještě kratší pomocí Here Strings , např.

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

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

nebo dokonce

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

pokud <<< není k dispozici, můžete použít např.

$ echo "1234567" | numfmt --to=iec-i --suffix=B
1.2MiB
1
craeckie
[email protected]:/usr$ alias duh="du -s -B1 * | sort -g | numfmt --to=iec-i --format='%10f'"
[email protected]:/usr$ duh

Dává:

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

Bohužel nemůžu přijít na to, jak získat přesnost na dvě desetinná místa. Testováno na Ubuntu 14.04.

1
Chris

Existují nástroje Pythonu

$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

Nevidím --binární příznak :(, takže pro binární reprezentaci byste museli použít python):

$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
ThorSummoner

Odpověď na vaši otázku zní ano.

Zatímco výstupní formát není přesně podle vaší specifikace, samotná konverze se snadno provádí pomocí velmi standardního nástroje (nebo dvou) . Těmi, na které odkazuji, jsou dc a bc. Segmentovaný výkaz můžete získat změnou jejich výstupních radic. Takhle:

{   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

... který tiskne ...

 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

Používám dc výše, protože je to osobní favorit, ale bc může dělat to samé s různou syntaxí a dodržuje stejná formátovací pravidla, jak je specifikována v POSIXu jako:

  • bc obase

    • U základen vyšších než 16 se každá číslice zapisuje jako samostatné víceciferné desetinné číslo. Každému číslu kromě nejvýznamnější zlomkové číslice musí předcházet jeden mezera . Pro základny od 17 do 100, bc zapíše dvouciferná desetinná čísla; pro základny od 101 do 1000, třímístné desetinné řetězce atd. Například desetinné číslo 1024 v základně 25 bude zapsáno takto:

    01 15 24

    a v základně 125 jako:

    008 024

0
mikeserv

pip install humanfriendly a poté do výchozího prostředí Shell přidejte jednoduchou funkci (např. ~/.bashrc)

function fsize() { humanfriendly --format-size `stat -f '%z' $1` }

Použijte takto

➜ fsize file.txt
6.17 KB
0
Most Wanted

Pokud můžete použít Python a pip, můžete to vyřešit pomocí humanize . (Díky Pyrocateru pro nápad .)

$ pip install humanize
$ bytes=35672345337
$ python -c "import humanize; print(humanize.naturalsize($bytes))"

35.7 GB

$ seq 0 750000 2250000 |python -c $'import sys, humanize\nfor n in sys.stdin: print(humanize.naturalsize(n))'

0 Bytes
750.0 kB
1.5 MB
2.2 MB
0
Bryan Roach