Skip to content

Commit

Permalink
cp,mv: reinstate that -n exits with success if files skipped
Browse files Browse the repository at this point in the history
* src/cp.c (main): Adjust so that -n will exit success if skipped files.
* src/mv.c (main): Likewise.
* doc/coreutils.texi (cp invocation): Adjust the description of -n.
* src/system.h (emit_update_parameters_note): Adjust --update=none
comparison.
* tests/cp/cp-i.sh: Adjust -n exit status checks.
* tests/mv/mv-n.sh: Likewise.
* NEWS: Mention the change in behavior.
Fixes https://bugs.gnu.org/62572
  • Loading branch information
pixelb committed Feb 26, 2024
1 parent 3bbdb39 commit 9907b6f
Show file tree
Hide file tree
Showing 7 changed files with 36 additions and 32 deletions.
4 changes: 4 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ GNU coreutils NEWS -*- outline -*-
basenc --base16 -d now supports lower case hexadecimal characters.
Previously an error was given for lower case hex digits.

cp --no-clobber, and mv -n no longer exit with failure status if
existing files are encountered in the destination. Instead they revert
to the behavior from before v9.2, silently skipping existing files.

ls --dired now implies long format output without hyperlinks enabled,
and will take precedence over previously specified formats or hyperlink mode.

Expand Down
14 changes: 6 additions & 8 deletions doc/coreutils.texi
Original file line number Diff line number Diff line change
Expand Up @@ -9057,12 +9057,10 @@ a regular file in the destination tree.
@itemx --no-clobber
@opindex -n
@opindex --no-clobber
Do not overwrite an existing file; silently fail instead.
This option overrides a previous
@option{-i} option. This option is mutually exclusive with @option{-b} or
@option{--backup} option.
See also the @option{--update=none} option which will
skip existing files but not fail.
Do not overwrite an existing file; silently skip instead.
This option overrides a previous @option{-i} option.
This option is mutually exclusive with @option{-b} or @option{--backup} option.
See also the @option{--update} option.

@item -P
@itemx --no-dereference
Expand Down Expand Up @@ -9333,8 +9331,8 @@ This is the default operation when an @option{--update} option is not specified,
and results in all existing files in the destination being replaced.

@item none
This is similar to the @option{--no-clobber} option, in that no files in the
destination are replaced, but also skipping a file does not induce a failure.
This is like the deprecated @option{--no-clobber} option, where no files in the
destination are replaced, and also skipping a file does not induce a failure.

@item older
This is the default operation when @option{--update} is specified, and results
Expand Down
14 changes: 8 additions & 6 deletions src/cp.c
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,8 @@ Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.\n\
-L, --dereference always follow symbolic links in SOURCE\n\
"), stdout);
fputs (_("\
-n, --no-clobber ensure no existing files overwritten, and fail\n\
silently instead. See also --update\n\
-n, --no-clobber silently skip existing files.\n\
See also --update\n\
"), stdout);
fputs (_("\
-P, --no-dereference never follow symbolic links in SOURCE\n\
Expand Down Expand Up @@ -984,6 +984,7 @@ main (int argc, char **argv)
char *target_directory = nullptr;
bool no_target_directory = false;
char const *scontext = nullptr;
bool no_clobber = false;

initialize_main (&argc, &argv);
set_program_name (argv[0]);
Expand Down Expand Up @@ -1074,7 +1075,8 @@ main (int argc, char **argv)
break;

case 'n':
x.interactive = I_ALWAYS_NO;
x.interactive = I_ALWAYS_SKIP;
no_clobber = true;
break;

case 'P':
Expand Down Expand Up @@ -1140,7 +1142,7 @@ main (int argc, char **argv)
case 'u':
if (optarg == nullptr)
x.update = true;
else if (x.interactive != I_ALWAYS_NO) /* -n takes precedence. */
else if (! no_clobber) /* -n takes precedence. */
{
enum Update_type update_opt;
update_opt = XARGMATCH ("--update", optarg,
Expand Down Expand Up @@ -1225,10 +1227,10 @@ main (int argc, char **argv)
usage (EXIT_FAILURE);
}

if (x.interactive == I_ALWAYS_NO)
if (x.interactive == I_ALWAYS_SKIP)
x.update = false;

if (make_backups && x.interactive == I_ALWAYS_NO)
if (make_backups && x.interactive == I_ALWAYS_SKIP)
{
error (0, 0,
_("options --backup and --no-clobber are mutually exclusive"));
Expand Down
10 changes: 6 additions & 4 deletions src/mv.c
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,7 @@ main (int argc, char **argv)
int n_files;
char **file;
bool selinux_enabled = (0 < is_selinux_enabled ());
bool no_clobber = false;

initialize_main (&argc, &argv);
set_program_name (argv[0]);
Expand Down Expand Up @@ -353,7 +354,8 @@ main (int argc, char **argv)
x.interactive = I_ASK_USER;
break;
case 'n':
x.interactive = I_ALWAYS_NO;
x.interactive = I_ALWAYS_SKIP;
no_clobber = true;
break;
case DEBUG_OPTION:
x.debug = x.verbose = true;
Expand All @@ -375,7 +377,7 @@ main (int argc, char **argv)
case 'u':
if (optarg == nullptr)
x.update = true;
else if (x.interactive != I_ALWAYS_NO) /* -n takes precedence. */
else if (! no_clobber) /* -n takes precedence. */
{
enum Update_type update_opt;
update_opt = XARGMATCH ("--update", optarg,
Expand Down Expand Up @@ -506,10 +508,10 @@ main (int argc, char **argv)
for (int i = 0; i < n_files; i++)
strip_trailing_slashes (file[i]);

if (x.interactive == I_ALWAYS_NO)
if (x.interactive == I_ALWAYS_SKIP)
x.update = false;

if (make_backups && x.interactive == I_ALWAYS_NO)
if (make_backups && x.interactive == I_ALWAYS_SKIP)
{
error (0, 0,
_("options --backup and --no-clobber are mutually exclusive"));
Expand Down
4 changes: 2 additions & 2 deletions src/system.h
Original file line number Diff line number Diff line change
Expand Up @@ -596,8 +596,8 @@ emit_update_parameters_note (void)
UPDATE controls which existing files in the destination are replaced.\n\
'all' is the default operation when an --update option is not specified,\n\
and results in all existing files in the destination being replaced.\n\
'none' is similar to the --no-clobber option, in that no files in the\n\
destination are replaced, but also skipped files do not induce a failure.\n\
'none' is like the --no-clobber option, in that no files in the\n\
destination are replaced, and skipped files do not induce a failure.\n\
'older' is the default operation when --update is specified, and results\n\
in files being replaced if they're older than the corresponding source file.\n\
"), stdout);
Expand Down
11 changes: 5 additions & 6 deletions tests/cp/cp-i.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ echo n | returns_ 1 cp -iR a b 2>/dev/null || fail=1
# test miscellaneous combinations of -f -i -n parameters
touch c d || framework_failure_
echo "'c' -> 'd'" > out_copy || framework_failure_
echo "cp: not replacing 'd'" > err_skip || framework_failure_
touch out_empty || framework_failure_

# ask for overwrite, answer no
Expand All @@ -45,24 +44,24 @@ echo y | cp -vni c d 2>/dev/null > out3 || fail=1
compare out3 out_copy || fail=1

# -n wins over -i
echo y | returns_ 1 cp -vin c d 2>/dev/null > out4 || fail=1
echo y | cp -vin c d 2>/dev/null > out4 || fail=1
compare out4 out_empty || fail=1

# -n wins over -i non verbose
echo y | returns_ 1 cp -in c d 2>err4 > out4 || fail=1
compare err4 err_skip || fail=1
echo y | cp -in c d 2>err4 > out4 || fail=1
compare /dev/null err4 || fail=1
compare out4 out_empty || fail=1

# ask for overwrite, answer yes
echo y | cp -vfi c d 2>/dev/null > out5 || fail=1
compare out5 out_copy || fail=1

# do not ask, prevent from overwrite
echo n | returns_ 1 cp -vfn c d 2>/dev/null > out6 || fail=1
echo n | cp -vfn c d 2>/dev/null > out6 || fail=1
compare out6 out_empty || fail=1

# do not ask, prevent from overwrite
echo n | returns_ 1 cp -vnf c d 2>/dev/null > out7 || fail=1
echo n | cp -vnf c d 2>/dev/null > out7 || fail=1
compare out7 out_empty || fail=1

# options --backup and --no-clobber are mutually exclusive
Expand Down
11 changes: 5 additions & 6 deletions tests/mv/mv-n.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ print_ver_ mv
# test miscellaneous combinations of -f -i -n parameters
touch a b || framework_failure_
echo "renamed 'a' -> 'b'" > out_move
echo "mv: not replacing 'b'" > err_skip || framework_failure_
> out_empty

# ask for overwrite, answer no
Expand All @@ -38,23 +37,23 @@ compare out2 out_move || fail=1

# -n wins (as the last option)
touch a b || framework_failure_
echo y | returns_ 1 mv -vin a b 2>/dev/null > out3 || fail=1
echo y | mv -vin a b 2>/dev/null > out3 || fail=1
compare out3 out_empty || fail=1

# -n wins (non verbose)
touch a b || framework_failure_
echo y | returns_ 1 mv -in a b 2>err3 > out3 || fail=1
echo y | mv -in a b 2>err3 > out3 || fail=1
compare out3 out_empty || fail=1
compare err3 err_skip || fail=1
compare /dev/null err3 || fail=1

# -n wins (as the last option)
touch a b || framework_failure_
echo y | returns_ 1 mv -vfn a b 2>/dev/null > out4 || fail=1
echo y | mv -vfn a b 2>/dev/null > out4 || fail=1
compare out4 out_empty || fail=1

# -n wins (as the last option)
touch a b || framework_failure_
echo y | returns_ 1 mv -vifn a b 2>/dev/null > out5 || fail=1
echo y | mv -vifn a b 2>/dev/null > out5 || fail=1
compare out5 out_empty || fail=1

# options --backup and --no-clobber are mutually exclusive
Expand Down

0 comments on commit 9907b6f

Please sign in to comment.