バイトカウントを人間のKiB MiBなどに変換する標準ツール。du、ls1など


94

1.00から1023.99の間の数値を維持しながら、バイトの整数カウントを人間が読める最大の単位サイズのカウントに変換する標準ツールはありますか?

私は自分のbash / awkスクリプトを持っていますが、多くの/ほとんどのディストリビューションで見られる標準ツールを探しています...より一般的に利用可能なもので、理想的には単純なコマンドライン引数を持ち、および/またはパイプ入力を受け入れることができます。

ここに私が探している出力の種類の例をいくつか示します。

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

これがバイト人間スクリプトです(上記の出力に使用)

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

 ここでの更新は、彼の答えに対するコメントで説明されているように、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}'

4
ここに新しいものがあるように見えますstandard tool:)
ゴーサム

@Gowtham-あなたの願いが叶ったかもしれません!以下の私の答えまたはblog.frankleonhardt.com/2015/…–
FJL

最後の2つの接尾辞が入れ替わっていることに注意してください。Yottabyteは実際にはZettabyteよりも大きいです。
staticfloat

回答:


89

いいえ、そのような標準ツールはありません。

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ソートは 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}'

より専門的な質問から再投稿


わかった、ありがとう。あなたのスクリプトについて、私は基本的にそれが本当に好きです。私の注意を引いたいくつかのことがあります:(1)var sはリードする必要がありBます。また、この文字列はIEC Binary表記に簡単に変更できます。(2)1000 < 1023の範囲をスキップして1 <次のサイズ>を優先します(簡単に変更できます)(3)10進数の値がありません(これは必要です)。繰り返しますが、これは簡単に変更できます。小数点以下2桁を表示する場合、%f形式により、round-up1019〜1023の <次のサイズ>になります。しかし、回避策の価値はありません。一般的な参考のために、修正版を回答に投稿しました。
Peter.O

coreutilsを使用するosx homebrewユーザーの
gnumfmt-詳細

du数値を人間が読み取れる形式に変換する場合は--block-size=1duコマンドに追加する必要がある場合があることに注意してください。
パワモイ

68

v。の時点では8.21、次のものがcoreutils含まれますnumfmt

numfmtさまざまな表現で数値を読み取り、要求に応じて再フォーマットします。
最も一般的な使用法は、数字を人間の表現に変換すること です。

例えば

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

(ETCフィルタリング、入力/出力処理を含む)様々な他の例が提示されているここ


さらに、coreutilsv。8.24では、とnumfmt同様のフィールド範囲指定で複数のフィールドを処理できcut--formatオプションで出力精度の設定をサポートします。
例:

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

numfmtは、coreutils-8.21以降のcoreutilsパッケージに新しく追加されたツールです。
ザマケス14年

1
これが、受け入れられた答えになるはずです。
アンディフォスター

23

これはbashのみのオプションであり、no bcまたはその他の非組み込みオプション、+ 10進形式、2進単位です。

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を含む)で良好に動作するはずです。


これは私のbashのニーズに最適な答えです。残念ながら、OPの日付から10年後に1/2が投稿されているため、投票リストを上に移動するにはしばらく時間がかかります。
WinEunuuchs2Unix

@ WinEunuuchs2Unixありがとう、私はそれがあなたに役立ってうれしいです:)
カミロマーティン

最後の2つの接尾辞が入れ替わっていることに注意してください。Yottabyteは実際にはZettabyteよりも大きいです。
staticfloat

6

これは、Peter.OのGillesのawkスクリプトの修正版に触発された完全な書き直しです。

変更点:

  • Peter.Oが1文字以上の文字列を検索し、4文字以上を検索する必要があるバグを修正します。そのバグのため、彼のコードはZiBユニットでは機能しません。
  • スペースで区切られたユニットサイズの長い文字列の非常にいハードコーディングを削除します。
  • パディングを有効/無効にするコマンドラインスイッチを追加します。
  • base-1024(KiB)表記からbase-1000(KB)表記に移行するコマンドラインスイッチを追加します。
  • 使いやすい機能ですべてをラップします。
  • 私はこれをパブリックドメインに置き、広範な使用を歓迎します。

コード:

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

楽しい!


5

perlCPANにはいくつかのモジュールがあります:Format :: Human :: BytesNumber :: Bytes :: Human、後者はもう少し完全です:

$ 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)で追加されました


5

Linux経由-バイト計算用のコマンドライン計算機はありますか?-Stack OverflowGNUユニットについて発見しました-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

3

実際、まさにこれを行うユーティリティがあります。私はそれが私がそれを書いたwotだったことを知っています。* BSD向けに書かれていますが、BSDライブラリがある場合はLinuxでコンパイルする必要があります(これは一般的だと思います)。

ここに投稿した新しいバージョンをリリースしました。

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

これはhrと呼ばれ、stdin(またはファイル)を取り、数値を人間が読める形式に変換します(現在はls -hなどとまったく同じです)。事前にスケールされたユニット(たとえば、512バイトブロックにある場合はMbなどに変換します)、列のパディングを調整します。

数年前に書いたのは、知的に興味深いものの、シェルスクリプトを記述しようとするのもまったくの狂気だと思ったからです。

たとえば、hrを使用すると、次のように、ディレクトリサイズのソート済みリスト(1Kb単位で出力され、変換する前にシフトする必要がある)を簡単に取得できます。

du -d1 | sort -n | hr -sK

duは-h出力を生成しますが、sortはそれによってソートしません。既存のユーティリティに-hを追加することは、Unixの哲学に従わない典型的なケースです。つまり、単純なユーティリティが定義されたジョブを非常にうまく実行するというものです。


2

これはほとんど純粋に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

1
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でテスト済み。


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

1

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

1

私は同じ問題を抱えていましたが、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]
  }
'

そして、浮動小数点数を使用する際に失われる精度は、その精度がとにかく失われるため、それほど悪くはありません。


0

あなたの質問に対する答えはイエスです。

出力形式は仕様どおりではありませんが、変換自体は非常に標準的なツール(または2つ)で簡単に実行できます。私が参照するものはdcbcです。出力基数を変更することにより、セグメント化されたレポートを取得できます。このような:

{   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 肥満

    • 16を超える基数の場合、各桁は個別の複数桁の10進数として書き込まれます。最も重要な分数桁を除いた各桁の前に単一のスペースがあるものとします。17から100までのbc基数の場合、2桁の10進数を書きます。101〜1000の基数、3桁の10進数文字列など。たとえば、基数25の10進数1024は次のように記述されます。

    01 15 24

    およびベース125で、次のように:

    008 024


-1

短くて甘い、シェルのみのソリューション:

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
}

小数のポーションは表示されません。

let VAR=expressionコーンっぽいです。VAR=$(( expression ))Born-again-ishの代わりに。


/ 1024は常に丸められるため、このソリューションでは大量のエラーが発生します。1.5TiBを2 TiBに切り上げたくないと確信しています。
ジェフリー

-2

私の知る限り、テキストを渡すことができるような標準ツールはなく、人間が読める形式を返します。ディストリビューションのタスクを実行するためのパッケージを見つけることができる場合があります。

ただし、このようなツールが必要になる理由はわかりません。関連する出力を提供するほとんどのパッケージには、通常、人間が読める出力用の-hまたは同等のスイッチがあります。


1
理解の目的:人間が読めるとは、まさにそれを意味します。人間が読める。言及したツールが示すさまざまなサイズの単位は、プログラムによる計算を目的としておらず、単位の均一性が不可欠です。常に整数であるバイトを操作することが、bashがそれらを使用して算術を行うことができる唯一の方法です。だから... バイトで計算... 人間でレポート、例えば。「3つのファイルを完全に削除しようとしています。合計2.44 GiBです。続行しますか?
-Peter.O

これはあなたの質問の一部であるべきだと思います。問題が解決したように見えます。幸運を。
シェルター

1
一般的なアプリケーションは、ソート用のバイト数を生成し、ソート後に人間が読める単位に変換することです。
ジル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.