Disk-Usage

為什麼 df 和 df -h 顯示不同的值?df -h 如何進行計算?

  • August 22, 2018

df -h 究竟是如何工作的?如果我執行df,我會得到這個:

Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/simfs      41943040 7659828  34283212  19% /

如果我執行df -h,我會得到這個:

Filesystem      Size  Used Avail Use% Mounted on
/dev/simfs       40G  7.4G   33G  19% /

問題是如何獲得相同的數字?

41943040 / 1024 / 1024 = 40 好的,讓我們除以 1024。

7659828 / 1024 / 1024 = 7,304981

然後可能是1000?

7659828 / 1000 / 1000 = 7,659828

df -h7.4G是怎麼來的?

34283212 / 1024 / 1024 = 32,695, which is ±33G

雖然 df 是開源的,但我已經複製了 repo 並檢查了程式碼。這就是我發現的:

for (col = 0; col < ncolumns; col++)
   {
     char *cell = NULL;
     char const *header = _(columns[col]->caption);

     if (columns[col]->field == SIZE_FIELD
         && (header_mode == DEFAULT_MODE
             || (header_mode == OUTPUT_MODE
                 && !(human_output_opts & human_autoscale))))
       {
         char buf[LONGEST_HUMAN_READABLE + 1];

         int opts = (human_suppress_point_zero
                     | human_autoscale | human_SI
                     | (human_output_opts
                        & (human_group_digits | human_base_1024 | human_B)));

         /* Prefer the base that makes the human-readable value more exact,
            if there is a difference.  */

         uintmax_t q1000 = output_block_size;
         uintmax_t q1024 = output_block_size;
         bool divisible_by_1000;
         bool divisible_by_1024;

         do
           {
             divisible_by_1000 = q1000 % 1000 == 0;  q1000 /= 1000;
             divisible_by_1024 = q1024 % 1024 == 0;  q1024 /= 1024;
           }
         while (divisible_by_1000 & divisible_by_1024);

         if (divisible_by_1000 < divisible_by_1024)
           opts |= human_base_1024;
         if (divisible_by_1024 < divisible_by_1000)
           opts &= ~human_base_1024;
         if (! (opts & human_base_1024))
           opts |= human_B;

         char *num = human_readable (output_block_size, buf, opts, 1, 1);

         /* Reset the header back to the default in OUTPUT_MODE.  */
         header = _("blocks");

         /* TRANSLATORS: this is the "1K-blocks" header in "df" output.  */
         if (asprintf (&cell, _("%s-%s"), num, header) == -1)
           cell = NULL;
       }
     else if (header_mode == POSIX_MODE && columns[col]->field == SIZE_FIELD)
       {
         char buf[INT_BUFSIZE_BOUND (uintmax_t)];
         char *num = umaxtostr (output_block_size, buf);

         /* TRANSLATORS: this is the "1024-blocks" header in "df -P".  */
         if (asprintf (&cell, _("%s-%s"), num, header) == -1)
           cell = NULL;
       }
     else
       cell = strdup (header);

     if (!cell)
       xalloc_die ();

     hide_problematic_chars (cell);

     table[nrows - 1][col] = cell;

     columns[col]->width = MAX (columns[col]->width, mbswidth (cell, 0));
   }

我沒有使用這種語言的經驗,但據我所知,它會嘗試檢查每列上的值是否可被 1024 或 1000 整除,並選擇更好的值來呈現-h選項的值。但是無論我除以 1000 還是 1024,我都沒有得到相同的值。為什麼?

我想我知道為什麼。它檢查在每個除法上除以 1000 或 1024。

         if (divisible_by_1000 < divisible_by_1024)
           opts |= human_base_1024;
         if (divisible_by_1024 < divisible_by_1000)
           opts &= ~human_base_1024;
         if (! (opts & human_base_1024))
           opts |= human_B;

所以讓我們破解 7659828 / 1024 / 1024 = 7,304981。-h給出了7.4G的答案

7659828 / 1024 = 7480,xxx
7659828 / 1000 = 7659,xxx

而 7659 大於 7480,除以 1024。

仍然是一個很大的數字,讓我們繼續:

7659828 / 1024 / 1024 = 7,xxx  (7,3049..)
7659828 / 1024 / 1000 = 7,xxx  (7,4803..)

它現在需要 1000 並給出 7,48,我相信在程式碼中的某個地方它會向下舍入,所以“最好說少而不是多”,而您可以輸入 7.4G 的數據,但不能輸入 7.5G。

與 33.4G 相同的故事

34283212 / 1024 / 1000 = 33.47...

所以變成了33G。

您發布的程式碼來自函式“get_header”,該函式在第一行生成文本。在您的情況下,這適用於標題“1K-blocks”(致電df -B1023查看差異)。

需要注意的重要一點:“1K”指的是 1024 字節的塊,而不是 1000 字節的塊(用“1kB-blocks”表示,請參閱df -B1000

人類可讀格式的數字計算由函式“human_readable”(human.c:153)處理。在 df.c:1571 中,您可以找到使用-h標誌呼叫時使用的選項:

case 'h':
   human_output_opts = human_autoscale | human_SI | human_base_1024;
   output_block_size = 1;
   break;

所有計算均以人類可讀格式(“-h”)的基數 1024 完成。除了顯示的 human_output_opts 之外,還有一個適用於此處的預設設置(參見 human.h,列舉聲明):

/* The following three options are mutually exclusive.  */
/* Round to plus infinity (default).  */
human_ceiling = 0,
/* Round to nearest, ties to even.  */
human_round_to_nearest = 1,
/* Round to minus infinity.  */
human_floor = 2,

由於human_output_opts 不包括human_round_to_nearest 或human_floor,它將使用其預設值human_ceiling。因此,所有計算值都將向上取整。

為了驗證設置,我們可以嘗試根據 1K 塊計算人類可讀的格式df

Size = ceil(41943040/1024/1024) = ceil(40) = 40
Used = ceil(7659828/1024/1024) = ceil(7.305) = 7.4
Available = ceil(34283212/1024/1024) = ceil(32.695) = 33

這與 的輸出相同df -h

(…如果您更喜歡 1000 字節格式,您可以簡單地呼叫df -H)。

引用自:https://unix.stackexchange.com/questions/446999