1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 03:27:44 +00:00

du: give -h output the same precision as GNU coreutils

When printing the `du -h` output GNU coreutils does autoscale
the size, e.g.
```
$ truncate -s12M a
$ truncate -s8500 b
$ truncate -s133456345 c
$ truncate -s56990456345 d
$ du -h --apparent-size a b c d
12M	a
8,4K	b
128M	c
54G	d
```
Align our version to do the same by sharing the code with `ls`.

Closes: #6159
This commit is contained in:
Michael Vogt 2024-04-01 09:59:21 +02:00 committed by Daniel Hofstetter
parent d07fb73630
commit 61e0450c66
3 changed files with 41 additions and 19 deletions

View file

@ -19,7 +19,7 @@ chrono = { workspace = true }
# For the --exclude & --exclude-from options # For the --exclude & --exclude-from options
glob = { workspace = true } glob = { workspace = true }
clap = { workspace = true } clap = { workspace = true }
uucore = { workspace = true } uucore = { workspace = true, features = ["format"] }
[target.'cfg(target_os = "windows")'.dependencies] [target.'cfg(target_os = "windows")'.dependencies]
windows-sys = { workspace = true, features = [ windows-sys = { workspace = true, features = [

View file

@ -75,9 +75,6 @@ const ABOUT: &str = help_about!("du.md");
const AFTER_HELP: &str = help_section!("after help", "du.md"); const AFTER_HELP: &str = help_section!("after help", "du.md");
const USAGE: &str = help_usage!("du.md"); const USAGE: &str = help_usage!("du.md");
// TODO: Support Z & Y (currently limited by size of u64)
const UNITS: [(char, u32); 6] = [('E', 6), ('P', 5), ('T', 4), ('G', 3), ('M', 2), ('K', 1)];
struct TraversalOptions { struct TraversalOptions {
all: bool, all: bool,
separate_dirs: bool, separate_dirs: bool,
@ -117,7 +114,8 @@ enum Time {
#[derive(Clone)] #[derive(Clone)]
enum SizeFormat { enum SizeFormat {
Human(u64), HumanDecimal,
HumanBinary,
BlockSize(u64), BlockSize(u64),
} }
@ -549,18 +547,14 @@ impl StatPrinter {
return size.to_string(); return size.to_string();
} }
match self.size_format { match self.size_format {
SizeFormat::Human(multiplier) => { SizeFormat::HumanDecimal => uucore::format::human::human_readable(
if size == 0 { size,
return "0".to_string(); uucore::format::human::SizeFormat::Decimal,
} ),
for &(unit, power) in &UNITS { SizeFormat::HumanBinary => uucore::format::human::human_readable(
let limit = multiplier.pow(power); size,
if size >= limit { uucore::format::human::SizeFormat::Binary,
return format!("{:.1}{}", (size as f64) / (limit as f64), unit); ),
}
}
format!("{size}B")
}
SizeFormat::BlockSize(block_size) => div_ceil(size, block_size).to_string(), SizeFormat::BlockSize(block_size) => div_ceil(size, block_size).to_string(),
} }
} }
@ -688,9 +682,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
}); });
let size_format = if matches.get_flag(options::HUMAN_READABLE) { let size_format = if matches.get_flag(options::HUMAN_READABLE) {
SizeFormat::Human(1024) SizeFormat::HumanBinary
} else if matches.get_flag(options::SI) { } else if matches.get_flag(options::SI) {
SizeFormat::Human(1000) SizeFormat::HumanDecimal
} else if matches.get_flag(options::BYTES) { } else if matches.get_flag(options::BYTES) {
SizeFormat::BlockSize(1) SizeFormat::BlockSize(1)
} else if matches.get_flag(options::BLOCK_SIZE_1K) { } else if matches.get_flag(options::BLOCK_SIZE_1K) {

View file

@ -543,6 +543,34 @@ fn test_du_h_flag_empty_file() {
.stdout_only("0\tempty.txt\n"); .stdout_only("0\tempty.txt\n");
} }
#[test]
fn test_du_h_precision() {
let test_cases = [
(133456345, "128M"),
(12 * 1024 * 1024, "12M"),
(8500, "8.4K"),
];
for &(test_len, expected_output) in &test_cases {
let (at, mut ucmd) = at_and_ucmd!();
let fpath = at.plus("test.txt");
std::fs::File::create(&fpath)
.expect("cannot create test file")
.set_len(test_len)
.expect("cannot truncate test len to size");
ucmd.arg("-h")
.arg("--apparent-size")
.arg(&fpath)
.succeeds()
.stdout_only(format!(
"{}\t{}\n",
expected_output,
&fpath.to_string_lossy()
));
}
}
#[cfg(feature = "touch")] #[cfg(feature = "touch")]
#[test] #[test]
fn test_du_time() { fn test_du_time() {