Skip to content

Commit 658af93

Browse files
committed
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
1 parent f8823f1 commit 658af93

File tree

3 files changed

+41
-19
lines changed

3 files changed

+41
-19
lines changed

src/uu/du/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ chrono = { workspace = true }
1919
# For the --exclude & --exclude-from options
2020
glob = { workspace = true }
2121
clap = { workspace = true }
22-
uucore = { workspace = true }
22+
uucore = { workspace = true, features = ["format"] }
2323

2424
[target.'cfg(target_os = "windows")'.dependencies]
2525
windows-sys = { workspace = true, features = [

src/uu/du/src/du.rs

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,6 @@ const ABOUT: &str = help_about!("du.md");
7474
const AFTER_HELP: &str = help_section!("after help", "du.md");
7575
const USAGE: &str = help_usage!("du.md");
7676

77-
// TODO: Support Z & Y (currently limited by size of u64)
78-
const UNITS: [(char, u32); 6] = [('E', 6), ('P', 5), ('T', 4), ('G', 3), ('M', 2), ('K', 1)];
79-
8077
struct TraversalOptions {
8178
all: bool,
8279
separate_dirs: bool,
@@ -116,7 +113,8 @@ enum Time {
116113

117114
#[derive(Clone)]
118115
enum SizeFormat {
119-
Human(u64),
116+
HumanDecimal,
117+
HumanBinary,
120118
BlockSize(u64),
121119
}
122120

@@ -548,18 +546,14 @@ impl StatPrinter {
548546
return size.to_string();
549547
}
550548
match self.size_format {
551-
SizeFormat::Human(multiplier) => {
552-
if size == 0 {
553-
return "0".to_string();
554-
}
555-
for &(unit, power) in &UNITS {
556-
let limit = multiplier.pow(power);
557-
if size >= limit {
558-
return format!("{:.1}{}", (size as f64) / (limit as f64), unit);
559-
}
560-
}
561-
format!("{size}B")
562-
}
549+
SizeFormat::HumanDecimal => uucore::format::human::human_readable(
550+
size,
551+
uucore::format::human::SizeFormat::Decimal,
552+
),
553+
SizeFormat::HumanBinary => uucore::format::human::human_readable(
554+
size,
555+
uucore::format::human::SizeFormat::Binary,
556+
),
563557
SizeFormat::BlockSize(block_size) => div_ceil(size, block_size).to_string(),
564558
}
565559
}
@@ -687,9 +681,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
687681
});
688682

689683
let size_format = if matches.get_flag(options::HUMAN_READABLE) {
690-
SizeFormat::Human(1024)
684+
SizeFormat::HumanBinary
691685
} else if matches.get_flag(options::SI) {
692-
SizeFormat::Human(1000)
686+
SizeFormat::HumanDecimal
693687
} else if matches.get_flag(options::BYTES) {
694688
SizeFormat::BlockSize(1)
695689
} else if matches.get_flag(options::BLOCK_SIZE_1K) {

tests/by-util/test_du.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,34 @@ fn test_du_h_flag_empty_file() {
543543
.stdout_only("0\tempty.txt\n");
544544
}
545545

546+
#[test]
547+
fn test_du_h_precision() {
548+
let test_cases = [
549+
(133456345, "128M"),
550+
(12 * 1024 * 1024, "12M"),
551+
(8500, "8.4K"),
552+
];
553+
554+
for &(test_len, expected_output) in &test_cases {
555+
let (at, mut ucmd) = at_and_ucmd!();
556+
557+
let fpath = at.plus("test.txt");
558+
std::fs::File::create(&fpath)
559+
.expect("cannot create test file")
560+
.set_len(test_len)
561+
.expect("cannot truncate test len to size");
562+
ucmd.arg("-h")
563+
.arg("--apparent-size")
564+
.arg(&fpath)
565+
.succeeds()
566+
.stdout_only(format!(
567+
"{}\t{}\n",
568+
expected_output,
569+
&fpath.to_string_lossy()
570+
));
571+
}
572+
}
573+
546574
#[cfg(feature = "touch")]
547575
#[test]
548576
fn test_du_time() {

0 commit comments

Comments
 (0)