cp now accepts the --keep-directory-symlink option (like tar), to preserve
and follow exisiting symlinks to directories in the destination.
+ cp and mv now accept the --update=none-fail option, which is similar
+ to the --no-clobber option, except that existing files are diagnosed,
+ and the command exits with failure status if existing files.
+ The -n,--no-clobber option is best avoided due to platform differences.
+
od now supports printing IEEE half precision floating point with -t fH,
or brain 16 bit floating point with -t fB, where supported by the compiler.
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.
+This option is deprecated due to having a different exit status from
+other platforms. See also the @option{--update} option which will
+give more control over how to deal with existing files in the destination,
+and over the exit status in particular.
@item -P
@itemx --no-dereference
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 none-fail
+This is similar to @samp{none}, in that no files in the destination
+are replaced, but any skipped files are diagnosed and induce a failure.
+
@item older
This is the default operation when @option{--update} is specified, and results
in files being replaced if they're older than the corresponding source file.
/* Leave existing files. */
UPDATE_NONE,
+
+ /* Leave existing files, but exit failure if existing files. */
+ UPDATE_NONE_FAIL,
};
/* This type is used to help mv (via copy.c) distinguish these cases. */
{"force", no_argument, nullptr, 'f'},
{"interactive", no_argument, nullptr, 'i'},
{"link", no_argument, nullptr, 'l'},
- {"no-clobber", no_argument, nullptr, 'n'},
+ {"no-clobber", no_argument, nullptr, 'n'}, /* Deprecated. */
{"no-dereference", no_argument, nullptr, 'P'},
{"no-preserve", required_argument, nullptr, NO_PRESERVE_ATTRIBUTES_OPTION},
{"no-target-directory", no_argument, nullptr, 'T'},
-L, --dereference always follow symbolic links in SOURCE\n\
"), stdout);
fputs (_("\
- -n, --no-clobber silently skip existing files.\n\
+ -n, --no-clobber (deprecated) silently skip exisiting files.\n\
See also --update\n\
"), stdout);
fputs (_("\
"), stdout);
fputs (_("\
--update[=UPDATE] control which existing files are updated;\n\
- UPDATE={all,none,older(default)}. See below\n\
- -u equivalent to --update[=older]\n\
+ UPDATE={all,none,none-fail,older(default)}.\n\
+ -u equivalent to --update[=older]. See below\n\
"), stdout);
fputs (_("\
-v, --verbose explain what is being done\n\
case 'n':
x.interactive = I_ALWAYS_SKIP;
no_clobber = true;
+ x.update = false;
break;
case 'P':
break;
case 'u':
- if (optarg == nullptr)
- x.update = true;
- else if (! no_clobber) /* -n takes precedence. */
+ if (! no_clobber) /* -n > -u */
{
- enum Update_type update_opt;
- update_opt = XARGMATCH ("--update", optarg,
- update_type_string, update_type);
+ enum Update_type update_opt = UPDATE_OLDER;
+ if (optarg)
+ update_opt = XARGMATCH ("--update", optarg,
+ update_type_string, update_type);
if (update_opt == UPDATE_ALL)
{
/* Default cp operation. */
x.update = false;
x.interactive = I_ALWAYS_SKIP;
}
+ else if (update_opt == UPDATE_NONE_FAIL)
+ {
+ x.update = false;
+ x.interactive = I_ALWAYS_NO;
+ }
else if (update_opt == UPDATE_OLDER)
{
x.update = true;
usage (EXIT_FAILURE);
}
- if (x.interactive == I_ALWAYS_SKIP)
- x.update = false;
-
- if (make_backups && x.interactive == I_ALWAYS_SKIP)
+ if (make_backups
+ && (x.interactive == I_ALWAYS_SKIP
+ || x.interactive == I_ALWAYS_NO))
{
error (0, 0,
- _("options --backup and --no-clobber are mutually exclusive"));
+ _("--backup is mutually exclusive with -n or --update=none-fail"));
usage (EXIT_FAILURE);
}
static char const *const update_type_string[] =
{
- "all", "none", "older", nullptr
+ "all", "none", "none-fail", "older", nullptr
};
static enum Update_type const update_type[] =
{
- UPDATE_ALL, UPDATE_NONE, UPDATE_OLDER,
+ UPDATE_ALL, UPDATE_NONE, UPDATE_NONE_FAIL, UPDATE_OLDER,
};
ARGMATCH_VERIFY (update_type_string, update_type);
{"debug", no_argument, nullptr, DEBUG_OPTION},
{"force", no_argument, nullptr, 'f'},
{"interactive", no_argument, nullptr, 'i'},
- {"no-clobber", no_argument, nullptr, 'n'},
+ {"no-clobber", no_argument, nullptr, 'n'}, /* Deprecated. */
{"no-copy", no_argument, nullptr, NO_COPY_OPTION},
{"no-target-directory", no_argument, nullptr, 'T'},
{"strip-trailing-slashes", no_argument, nullptr,
"), stdout);
fputs (_("\
--update[=UPDATE] control which existing files are updated;\n\
- UPDATE={all,none,older(default)}. See below\n\
- -u equivalent to --update[=older]\n\
+ UPDATE={all,none,none-fail,older(default)}.\n\
+ -u equivalent to --update[=older]. See below\n\
"), stdout);
fputs (_("\
-v, --verbose explain what is being done\n\
case 'n':
x.interactive = I_ALWAYS_SKIP;
no_clobber = true;
+ x.update = false;
break;
case DEBUG_OPTION:
x.debug = x.verbose = true;
no_target_directory = true;
break;
case 'u':
- if (optarg == nullptr)
- x.update = true;
- else if (! no_clobber) /* -n takes precedence. */
+ if (! no_clobber)
{
- enum Update_type update_opt;
- update_opt = XARGMATCH ("--update", optarg,
- update_type_string, update_type);
+ enum Update_type update_opt = UPDATE_OLDER;
+ if (optarg)
+ update_opt = XARGMATCH ("--update", optarg,
+ update_type_string, update_type);
if (update_opt == UPDATE_ALL)
{
/* Default mv operation. */
x.update = false;
x.interactive = I_ALWAYS_SKIP;
}
+ else if (update_opt == UPDATE_NONE_FAIL)
+ {
+ x.update = false;
+ x.interactive = I_ALWAYS_NO;
+ }
else if (update_opt == UPDATE_OLDER)
{
x.update = true;
for (int i = 0; i < n_files; i++)
strip_trailing_slashes (file[i]);
- if (x.interactive == I_ALWAYS_SKIP)
- x.update = false;
-
- if (make_backups && x.interactive == I_ALWAYS_SKIP)
+ if (make_backups
+ && (x.interactive == I_ALWAYS_SKIP
+ || x.interactive == I_ALWAYS_NO))
{
error (0, 0,
- _("options --backup and --no-clobber are mutually exclusive"));
+ _("--backup is mutually exclusive with -n or --update=none-fail"));
usage (EXIT_FAILURE);
}
and results in all existing files in the destination being replaced.\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\
+'none-fail' also ensures no files are replaced in the destination,\n\
+but any skipped files are diagnosed and 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);
# options --backup and --no-clobber are mutually exclusive
returns_ 1 cp -bn c d 2>/dev/null || fail=1
+# options --backup and --update=none{,-fail} are mutually exclusive
+returns_ 1 cp -b --update=none c d 2>/dev/null || fail=1
+returns_ 1 cp -b --update=none-fail c d 2>/dev/null || fail=1
Exit $fail
# options --backup and --no-clobber are mutually exclusive
touch a || framework_failure_
returns_ 1 mv -bn a b 2>/dev/null || fail=1
+# options --backup and --update=none{,-fail} are mutually exclusive
+returns_ 1 mv -b --update=none a b 2>/dev/null || fail=1
+returns_ 1 mv -b --update=none-fail a b 2>/dev/null || fail=1
Exit $fail
done
# These should not perform the rename / copy
-for update_option in '--update=none' \
- '--update=all --update=none'; do
+for update_option in '--update=none' '--update=none-fail' \
+ '--update=all --update=none' \
+ '--update=all --no-clobber' \
+ '--no-clobber --update=all'; do
+
+ echo "$update_option" | grep 'fail' >/dev/null && ret=1 || ret=0
+
test_reset
- mv $update_option new old || fail=1
+ returns_ $ret mv $update_option new old || fail=1
case "$(cat new)" in new) ;; *) fail=1 ;; esac
case "$(cat old)" in old) ;; *) fail=1 ;; esac
test_reset
- cp $update_option new old || fail=1
+ returns_ $ret cp $update_option new old || fail=1
case "$(cat new)" in new) ;; *) fail=1 ;; esac
case "$(cat old)" in old) ;; *) fail=1 ;; esac
done