1.00から1023.99までの数値を維持しながら、バイト数の整数カウントを人間が読める最大のユニットサイズのカウントに変換する標準ツールはありますか?
私は自分のbash/awkスクリプトを持っていますが、多くの/ほとんどのディストリビューションにあるstandardツールを探しています...もっと一般的に利用できるもので、理想的には単純なコマンドライン引数があり、 /またはパイプ入力を受け入れることができます。
以下は、私が探している出力タイプの例です。
1 Byt
173.00 KiB
46.57 MiB
1.84 GiB
29.23 GiB
265.72 GiB
1.63 TiB
これがbytes-humanスクリプトです(上記の出力に使用されます)
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 )
}'
pdateここにGilles 'スクリプトの修正バージョンがあります。彼の回答へのコメントに記載されています..(私の好みの外観に合わせて修正されました)。
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}'
いいえ、そのような標準的なツールはありません。
GNU coreutils 8.21(2013年2月、まだすべてのディストリビューションに存在しない))なので、非組み込みLinuxおよびCygwinでは、 numfmt
を使用できます。それは正確に同じ出力形式を生成しません(coreutils 8.23の時点で、小数点以下2桁を取得できないと思います)。
$ numfmt --to=iec-i --suffix=B --padding=7 1 177152 48832200 1975684956
1B
173KiB
47MiB
1.9GiB
多くの古いGNUツールはこの形式を生成できます GNU sortは数値を単位でソートできます coreutils 7.5以降(2009年8月、最新の非組み込みLinuxディストリビューションに存在)。
あなたのコードは少し複雑です。以下は、よりクリーンなawkバージョンです(出力形式は完全に同一ではありません)。
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}'
( より専門的な質問から再投稿 )
V。8.21
以降、coreutils
には numfmt
が含まれます:
numfmt
は、さまざまな表現で数値を読み取り、要求に応じて再フォーマットします。
最も一般的な使用法は、数値をhuman表現に/から変換することです。
例えば.
printf %s\\n 5607598768908 | numfmt --to=iec-i
5.2Ti
他のさまざまな例(フィルタリング、入力/出力処理など)を示します [〜#〜]ここ[〜#〜] 。
さらに、coreutils
v。8.24
以降、numfmt
はcut
と同様のフィールド範囲指定で複数のフィールドを処理でき、出力精度の設定をサポートしています。 --format
オプション
例えば。
numfmt --to=iec-i --field=2,4 --format='%.3f' <<<'tx: 180000 rx: 2000000'
tx:175.782Ki rx:1.908Mi
これはbashのみのオプションで、bc
やその他の非組み込み型はありません。+ 10進数形式とバイナリ単位。
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]}"
}
例:
$ bytesToHuman 123456789
117.73 MiB
$ bytesToHuman 1000000000000 # "1TB of storage"
931.32 GiB # 1TB of storage
$ bytesToHuman
0 Bytes
そこにあるすべてのバージョンのBash(MSYSGitのBash for Windowsを含む)で十分に機能するはずです。
linux-バイト計算用のコマンドライン計算機はありますか?-スタックオーバーフロー を使用して、 GNU Units について見つけましたが、SOページには例がありません。ここにリストされていなかったので、ここにそれについての小さなメモがあります。
まず、ユニットが存在するかどうかを確認します。
$ units --check-verbose |grep byte
doing 'byte'
$ units --check-verbose |grep mega
doing 'megalerg'
doing 'mega'
$ units --check-verbose |grep mebi
doing 'mebi'
それらがそうであれば、変換を行います-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
これは、GillesのawkスクリプトのPeter.Oの修正バージョンに触発された完全な書き直しです。
変更:
コード:
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 $?
}
テストケース(出力を確認する場合):
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}.";
楽しい!
CPANにはいくつかのPerl
モジュールがあります: Format :: Human :: Bytes および Number :: Bytes :: Human 、後者はaもう少し完全:
_$ 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
_
そしてその逆:
_$ 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
_
注:関数parse_bytes()
は バージョン0.09で追加されました(2013-03-01)
実際、これを正確に行うユーティリティがあります。私はそれが私がそれを書いたことだったのを知っています。これは* BSD用に書かれていますが、BSDライブラリがある場合はLinuxでコンパイルする必要があります(これは一般的だと思います)。
私はここに投稿された新しいバージョンをリリースしました:
http://blog.frankleonhardt.com/2015/freebsd-hr-utility-human-readable-number-filter-man-page/
これはhrと呼ばれ、標準入力(またはファイル)を受け取り、数値を人間が読める形式に変換します(現在はls -hとまったく同じ)事前にスケーリングされた単位(512バイトのブロックにある場合はMbなどに変換する)、列のパディングなどを調整します。
数年前に書いたのは、シェルスクリプトを書こうとすることは、知的には面白かったけれども、まったくの狂気だと思ったからです。
たとえば、hrを使用すると、次のようにして、ソートされたディレクトリサイズのリスト(1Kb単位で出力され、変換前にシフトする必要がある)を簡単に取得できます。
du -d1 |ソート-n | hr -sK
Duは-h出力を生成しますが、sortはそれによってソートしません。既存のユーティリティに-hを追加することは、UNIXの哲学に従わない典型的なケースです:定義されたジョブを実行する単純なユーティリティを本当に持っています。
これは、ほぼ純粋にbashで行う方法です。浮動小数点演算には「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
}
使用法:
bytesToHR 1
bytesToHR 1023
bytesToHR 1024
bytesToHR 12345
bytesToHR 123456
bytesToHR 1234567
bytesToHR 12345678
出力:
1 B
1023 B
1.00 KiB
12.06 KiB
120.56 KiB
1.18 MiB
11.77 MiB
同じ問題があり、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]
}
'
そして、浮動小数点数を使用したときに失われる精度はそれほど悪くありません。その精度はとにかく失われるからです。
@don_crisstiの最初の回答は適切ですが、 Here Strings を使用してさらに短くすることができます。
$ numfmt --to=iec-i <<< "12345"
13Ki
$ numfmt --to=iec-i --suffix=B <<< "1234567"
1.2MiB
あるいは
$ numfmt --from=iec-i --to=iec-i --suffix=B <<< "12345Ki"
13MiB
もし<<<
は使用できません。
$ echo "1234567" | numfmt --to=iec-i --suffix=B
1.2MiB
user@Host:/usr$ alias duh="du -s -B1 * | sort -g | numfmt --to=iec-i --format='%10f'"
user@Host:/usr$ duh
与える:
4.0Ki games
3.9Mi local
18Mi include
20Mi sbin
145Mi bin
215Mi share
325Mi src
538Mi lib
残念ながら、小数点以下2桁の精度を取得する方法がわかりません。 Ubuntu 14.04でテスト済み。
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
--binaryフラグ:(が表示されないので、バイナリ表現には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
あなたの質問への答えはイエスです。
出力形式は仕様どおりではありませんが、変換自体は非常に標準的なツール(または2つ)で簡単に実行できます。私が参照するのはdc
とbc
です。出力の基数を変更することで、セグメント化されたレポートを取得できます。このような:
{ 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
...印刷する...
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
上記のdc
は個人的なお気に入りなので使用しますが、bc
は、異なる構文で同じことを行うことができ、POSIXで指定されているものと同じフォーマット規則に従います。
bc
は2桁の10進数を書き込みます。基数が101から1000の場合、3桁の10進文字列など。たとえば、基数25の10進数1024は次のように記述されます。01 15 24
ベース125では、次のようになります。
008 024
pip install humanfriendly
次に、デフォルトのシェルに簡単な関数を追加します(例:~/.bashrc
)
function fsize() { humanfriendly --format-size `stat -f '%z' $1` }
このように使う
➜ fsize file.txt
6.17 KB
Pythonとpipを使用できる場合、これは humanize で解決できます( the idea のPyrocaterに感謝します)。
$ 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