
¿Cómo funciona exactamente df -h? Si ejecuto df
me sale esto:
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/simfs 41943040 7659828 34283212 19% /
Si ejecuto df -h
me sale esto:
Filesystem Size Used Avail Use% Mounted on
/dev/simfs 40G 7.4G 33G 19% /
La pregunta es ¿cómo obtener los mismos números?
41943040/1024/1024 = 40 Bien, dividamos los demás por 1024.
7659828 / 1024 / 1024 = 7,304981
¿Entonces tal vez para el año 1000?
7659828 / 1000 / 1000 = 7,659828
¿Cómo df -h
consiguió 7,4G?
34283212 / 1024 / 1024 = 32,695, which is ±33G
Si bien df es de código abierto, heclonadoel repositorio y verificó el código. Eso es lo que encontré:
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));
}
No tengo experiencia con este lenguaje, pero según tengo entendido, intenta verificar si el valor de cada columna es divisible por 1024 o 1000 y elige lo que sea mejor para representar los valores de la -h
opción. Pero no obtengo el mismo valor sin importar si lo divido entre 1000 o 1024. ¿Por qué?
Creo que sé por qué. Comprueba dividir por 1000 o 1024 encadadivisión.
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;
así que desciframos 7659828/1024/1024 = 7,304981.-h
dio respuesta de7,4G
7659828 / 1024 = 7480,xxx
7659828 / 1000 = 7659,xxx
mientras que 7659 es mayor que 7480, divídalo entre 1024.
Sigue siendo un número grande, continuemos:
7659828 / 1024 / 1024 = 7,xxx (7,3049..)
7659828 / 1024 / 1000 = 7,xxx (7,4803..)
se necesita 1000 ahora y da 7,48 y yocreerEn algún lugar del código se redondea hacia abajo, por lo que "es mejor decir menos que más", mientras que puedes ingresar 7,4G de datos pero no puedes ingresar 7,5G.
La misma historia con 33.4G
34283212 / 1024 / 1000 = 33.47...
Entonces se convierte en 33G.
Respuesta1
El código que publicó proviene de la función "get_header" que genera el texto en la primera fila. En su caso, esto se aplica al encabezado "1K-blocks" (llame df -B1023
para ver la diferencia).
Importante tener en cuenta: "1K" se refiere a bloques de 1024 bytes, no a bloques de 1000 bytes (indicados por "bloques de 1kB", consulte df -B1000
)
El cálculo de los números en formato legible por humanos se realiza mediante la función "human_readable" (human.c:153). En df.c:1571 puedes encontrar las opciones que se utilizan cuando se llama con la -h
bandera:
case 'h':
human_output_opts = human_autoscale | human_SI | human_base_1024;
output_block_size = 1;
break;
Todos los cálculos se realizan con base 1024 en formato legible por humanos ("-h"). Además de los human_output_opts mostrados, hay una configuración predeterminada que se aplica aquí (consulte human.h, declaración de enumeración):
/* 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,
Como human_output_opts no incluye human_round_to_nearest o human_floor, utilizará su valor predeterminado de human_ceiling. Por lo tanto, todos los valores calculados se redondearán hacia arriba.
Para verificar la configuración, podemos intentar calcular el formato legible por humanos en función de los bloques de 1K de 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
Que es lo mismo que la salida de df -h
.
(... y si prefieres el formato de 1000 bytes, puedes simplemente llamar df -H
).
Respuesta2
Ni el df
programa de FreeBSD (de aquí es df -h
originario) ni la df
implementación de Solaris se comportan de esta manera.
Dado que las fuentes de Solaris son OpenSource, puede verificar si puede compilar df
en su sistema operativo: