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}'
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}'
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
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).
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
Toto je kompletní přepis inspirovaný upravenou verzí Petera Oka awk skriptu.
Změny:
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!
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)
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.
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
Měl jsem stejný problém a rychle jsem přišel s jednoduchým řešením pomocí funkce awk
log()
:
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.
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
[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.
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
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
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
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
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