From ed0dd67fe6c8e9d8a8c4eec460730d9bf73068bf Mon Sep 17 00:00:00 2001 From: Tanbir Hossain Ramim <96797470+TanbirRamim@users.noreply.github.com> Date: Mon, 26 Oct 2026 00:50:15 +0100 Subject: [PATCH] df: let the last of -B, -h, -H, -k and -m win, like GNU --- src/uu/df/src/df.rs | 19 ++++++++++++++----- tests/by-util/test_df.rs | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/src/uu/df/src/df.rs b/src/uu/df/src/df.rs index 022b61d1196..e5c279dd82b 100644 --- a/src/uu/df/src/df.rs +++ b/src/uu/df/src/df.rs @@ -48,6 +48,15 @@ static OPT_HUMAN_READABLE_DECIMAL: &str = "human-readable-decimal"; static OPT_INODES: &str = "inodes"; static OPT_KILO: &str = "kilo"; static OPT_MEGA: &str = "mega"; +/// `-B`, `-h`, `-H`, `-k` and `-m` all pick how sizes are shown. Like GNU df, +/// whichever comes last on the command line wins, so each overrides the others. +static SIZE_OPTIONS: [&str; 5] = [ + "blocksize", + "human-readable-binary", + "human-readable-decimal", + "kilo", + "mega", +]; static OPT_LOCAL: &str = "local"; static OPT_NO_SYNC: &str = "no-sync"; static OPT_OUTPUT: &str = "output"; @@ -564,7 +573,7 @@ pub fn uu_app() -> Command { .short('B') .long(OPT_BLOCKSIZE_LONG) .value_name("SIZE") - .overrides_with_all([OPT_KILO, OPT_MEGA, OPT_BLOCKSIZE]) + .overrides_with_all(SIZE_OPTIONS) .help(translate!("df-help-block-size")), ) .arg( @@ -578,7 +587,7 @@ pub fn uu_app() -> Command { Arg::new(OPT_HUMAN_READABLE_BINARY) .short('h') .long("human-readable") - .overrides_with_all([OPT_HUMAN_READABLE_DECIMAL, OPT_HUMAN_READABLE_BINARY]) + .overrides_with_all(SIZE_OPTIONS) .help(translate!("df-help-human-readable")) .action(ArgAction::SetTrue), ) @@ -586,7 +595,7 @@ pub fn uu_app() -> Command { Arg::new(OPT_HUMAN_READABLE_DECIMAL) .short('H') .long("si") - .overrides_with_all([OPT_HUMAN_READABLE_BINARY, OPT_HUMAN_READABLE_DECIMAL]) + .overrides_with_all(SIZE_OPTIONS) .help(translate!("df-help-si")) .action(ArgAction::SetTrue), ) @@ -602,14 +611,14 @@ pub fn uu_app() -> Command { Arg::new(OPT_KILO) .short('k') .help(translate!("df-help-kilo")) - .overrides_with_all([OPT_BLOCKSIZE, OPT_KILO, OPT_MEGA]) + .overrides_with_all(SIZE_OPTIONS) .action(ArgAction::SetTrue), ) .arg( Arg::new(OPT_MEGA) .short('m') .help(translate!("df-help-mega")) - .overrides_with_all([OPT_BLOCKSIZE, OPT_KILO, OPT_MEGA]) + .overrides_with_all(SIZE_OPTIONS) .action(ArgAction::SetTrue), ) .arg( diff --git a/tests/by-util/test_df.rs b/tests/by-util/test_df.rs index 7f4ab559960..dc11725bca2 100644 --- a/tests/by-util/test_df.rs +++ b/tests/by-util/test_df.rs @@ -650,6 +650,43 @@ fn test_block_size_1m_option_with_output() { } } +#[test] +fn test_last_size_option_wins() { + // GNU df 9.11: -B, -h, -H, -k and -m override each other, the last one wins. + for (args, expected) in [ + (&["-h", "-B", "1K"][..], "1K-blocks"), + (&["-B", "1K", "-h"][..], "Size"), + (&["-h", "-k"][..], "1K-blocks"), + (&["-k", "-h"][..], "Size"), + (&["-H", "-k"][..], "1K-blocks"), + (&["-k", "-H"][..], "Size"), + (&["-h", "-m"][..], "1M-blocks"), + (&["-m", "-h"][..], "Size"), + ] { + let output = new_ucmd!() + .args(args) + .arg("--output=size") + .succeeds() + .stdout_str_lossy(); + let header = output.lines().next().unwrap().trim(); + + assert_eq!(header, expected, "df {}", args.join(" ")); + } +} + +#[test] +fn test_block_size_after_human_readable_sets_the_values() { + // The header alone would pass if only the header code followed the order, + // so also check the value is a plain block count, not a human size like "461G". + let output = new_ucmd!() + .args(&["-h", "-B", "1", "--output=size", "."]) + .succeeds() + .stdout_str_lossy(); + let value = output.lines().nth(1).unwrap().trim(); + + assert!(value.chars().all(|c| c.is_ascii_digit()), "got {value}"); +} + #[test] fn test_block_size_with_suffix() { fn get_header(block_size: &str) -> String {