diff --git a/src/uu/mv/mv.md b/src/uu/mv/mv.md index c31c6d07c..460e84a1d 100644 --- a/src/uu/mv/mv.md +++ b/src/uu/mv/mv.md @@ -9,6 +9,8 @@ Move `SOURCE` to `DEST`, or multiple `SOURCE`(s) to `DIRECTORY`. ## After Help +If you specify more than one of `-i`, `-f`, `-n`, only the final one takes effect. + Do not move a non-directory that has an existing destination with the same or newer modification timestamp; instead, silently skip the file without failing. If the move is across file system boundaries, the comparison is to the source timestamp truncated to the resolutions of the destination file system and of the system calls used diff --git a/src/uu/mv/src/mv.rs b/src/uu/mv/src/mv.rs index 9632ddabf..2a2d6d348 100644 --- a/src/uu/mv/src/mv.rs +++ b/src/uu/mv/src/mv.rs @@ -145,6 +145,7 @@ pub fn uu_app() -> Command { .short('f') .long(OPT_FORCE) .help("do not prompt before overwriting") + .overrides_with_all([OPT_INTERACTIVE, OPT_NO_CLOBBER]) .action(ArgAction::SetTrue), ) .arg( @@ -152,6 +153,7 @@ pub fn uu_app() -> Command { .short('i') .long(OPT_INTERACTIVE) .help("prompt before override") + .overrides_with_all([OPT_FORCE, OPT_NO_CLOBBER]) .action(ArgAction::SetTrue), ) .arg( @@ -159,6 +161,7 @@ pub fn uu_app() -> Command { .short('n') .long(OPT_NO_CLOBBER) .help("do not overwrite an existing file") + .overrides_with_all([OPT_FORCE, OPT_INTERACTIVE]) .action(ArgAction::SetTrue), ) .arg( diff --git a/tests/by-util/test_mv.rs b/tests/by-util/test_mv.rs index b3ecb33c2..edeb47a96 100644 --- a/tests/by-util/test_mv.rs +++ b/tests/by-util/test_mv.rs @@ -280,6 +280,41 @@ fn test_mv_interactive_dir_to_file_not_affirmative() { assert!(at.dir_exists(dir)); } +#[test] +fn test_mv_interactive_no_clobber_force_last_arg_wins() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + + let file_a = "a.txt"; + let file_b = "b.txt"; + + at.touch(file_a); + at.touch(file_b); + + scene + .ucmd() + .args(&[file_a, file_b, "-f", "-i", "-n"]) + .fails() + .stderr_is(format!("mv: not replacing '{file_b}'\n")); + + scene + .ucmd() + .args(&[file_a, file_b, "-n", "-f", "-i"]) + .fails() + .stderr_is(format!("mv: overwrite '{file_b}'? ")); + + at.write(file_a, "aa"); + + scene + .ucmd() + .args(&[file_a, file_b, "-i", "-n", "-f"]) + .succeeds() + .no_output(); + + assert!(!at.file_exists(file_a)); + assert_eq!("aa", at.read(file_b)); +} + #[test] fn test_mv_arg_update_interactive() { let (at, mut ucmd) = at_and_ucmd!();