-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 According to Jim Meyering on 2/17/2006 9:14 AM: > Eric Blake <[EMAIL PROTECTED]> wrote: > >>So you propose that --interactive alone be equivalant to >>--interactive=always or -i, and that the long option for -I is >>--interactive=once. Is it worth having a shorter spelling for the long >>option for -I? > > > No. Those who want `short' can use -I. > Although --ask-once does sound nice, I want to keep things minimal, > in case we end up providing similar functionality for other commands, > where adding a long-named synonym might make an existing abbreviation > ambiguous -- --ask-once would do just that to cp --a(rchive).
With that, here goes. Changes from the first submittal: --interactive without WHEN defaults to -i, NEWS and coreutils.texi touched up to match this change, and 2 test files are added. ChangeLog: 2006-02-18 Eric Blake <[EMAIL PROTECTED]> * TODO (rm): Implement rm -I. * NEWS: Document it, along with change to rm --interactive. * src/rm.c (INTERACTIVE_OPTION): New enum value. (interactive_type): New enum. (long_opts): Let interactive take an optional argument. (interactive_args, interactive_types): New option arguments. (usage): Document -I, --interactive=WHEN. Use program_name instead of a basename. (main): New -I option, new behavior to --interactive. * tests/rm/interactive-once: New tests. * tests/rm/interactive-always: Ditto. * tests/rm/Makefile.am (TESTS): Run them. doc/ChangeLog: 2006-02-18 Eric Blake <[EMAIL PROTECTED]> * coreutils.texi (rm invocation): Document new -I option, and new --interactive behavior. - -- Life is short - so eat dessert first! Eric Blake [EMAIL PROTECTED] -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.1 (Cygwin) Comment: Public key at home.comcast.net/~ericblake/eblake.gpg Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org iD8DBQFD92Ar84KuGfSFAYARAqMqAKCCnnycir0UCfAtE3IGy/JIz171tgCfeCg9 fIWbng1br9auGCIwYJrbYSE= =rWII -----END PGP SIGNATURE-----
Index: TODO =================================================================== RCS file: /sources/coreutils/coreutils/TODO,v retrieving revision 1.101 diff -u -p -r1.101 TODO --- TODO 16 Oct 2005 10:36:02 -0000 1.101 +++ TODO 18 Feb 2006 17:46:50 -0000 @@ -215,9 +215,3 @@ Adapt tools like wc, tr, fmt, etc. (most (preferably `no') cost when operating in single-byte mode. Remove all uses of the `register' keyword - -rm: add support for a -I option, like that from FreeBSD's rm: - -I Request confirmation once if more than three files are being - removed or if a directory is being recursively removed. This - is a far less intrusive option than -i yet provides almost - the same level of protection against mistakes. Index: NEWS =================================================================== RCS file: /sources/coreutils/coreutils/NEWS,v retrieving revision 1.359 diff -u -p -r1.359 NEWS --- NEWS 11 Feb 2006 19:25:26 -0000 1.359 +++ NEWS 18 Feb 2006 17:46:51 -0000 @@ -26,6 +26,9 @@ GNU coreutils NEWS if your locale settings appear to be messed up. This change attempts to have the default be the best of both worlds. + rm --interactive now takes an optional argument, although the + default of using no argument still acts like -i. + mkfifo and mknod no longer set special mode bits (setuid, setgid, and sticky) with the -m option. @@ -71,6 +74,12 @@ GNU coreutils NEWS updating its access time, on hosts that support this (currently only Linux kernels, version 2.6.8 and later). + rm now accepts the -I (--interactive=once) option. This new option + prompts once if rm is invoked recursively or if more than three + files are being deleted, which is less intrusive than -i prompting + for every file, but provides almost the same level of protection + against mistakes. + sort now accepts the --random-sort (-R) option and `R' ordering option, as well as the --seed=STRING option. Index: src/rm.c =================================================================== RCS file: /sources/coreutils/coreutils/src/rm.c,v retrieving revision 1.138 diff -u -p -r1.138 rm.c --- src/rm.c 6 Feb 2006 08:00:39 -0000 1.138 +++ src/rm.c 18 Feb 2006 17:46:52 -0000 @@ -49,6 +49,7 @@ #include <assert.h> #include "system.h" +#include "argmatch.h" #include "dirname.h" #include "error.h" #include "lstat.h" @@ -56,6 +57,7 @@ #include "quotearg.h" #include "remove.h" #include "root-dev-ino.h" +#include "yesno.h" /* The official name of this program (e.g., no `g' prefix). */ #define PROGRAM_NAME "rm" @@ -70,16 +72,24 @@ char *program_name; non-character as a pseudo short option, starting with CHAR_MAX + 1. */ enum { - NO_PRESERVE_ROOT = CHAR_MAX + 1, + INTERACTIVE_OPTION = CHAR_MAX + 1, + NO_PRESERVE_ROOT, PRESERVE_ROOT, PRESUME_INPUT_TTY_OPTION }; +enum interactive_type + { + interactive_never, /* 0: no option or --interactive=never */ + interactive_once, /* 1: -I or --interactive=once */ + interactive_always /* 2: default, -i or --interactive=always */ + }; + static struct option const long_opts[] = { {"directory", no_argument, NULL, 'd'}, {"force", no_argument, NULL, 'f'}, - {"interactive", no_argument, NULL, 'i'}, + {"interactive", optional_argument, NULL, INTERACTIVE_OPTION}, {"no-preserve-root", no_argument, NULL, NO_PRESERVE_ROOT}, {"preserve-root", no_argument, NULL, PRESERVE_ROOT}, @@ -97,6 +107,20 @@ static struct option const long_opts[] = {NULL, 0, NULL, 0} }; +static char const *const interactive_args[] = +{ + "never", "no", "none", + "once", + "always", "yes", NULL +}; +static enum interactive_type const interactive_types[] = +{ + interactive_never, interactive_never, interactive_never, + interactive_once, + interactive_always, interactive_always +}; +ARGMATCH_VERIFY (interactive_args, interactive_types); + /* Advise the user about invalid usages like "rm -foo" if the file "-foo" exists, assuming ARGC and ARGV are as with `main'. */ @@ -132,13 +156,19 @@ usage (int status) program_name); else { - char *base = base_name (program_name); printf (_("Usage: %s [OPTION]... FILE...\n"), program_name); fputs (_("\ Remove (unlink) the FILE(s).\n\ \n\ -f, --force ignore nonexistent files, never prompt\n\ - -i, --interactive prompt before any removal\n\ + -i prompt before every removal\n\ +"), stdout); + fputs (_("\ + -I prompt once before removing more than three files, or\n\ + when removing recursively. Less intrusive than -i,\n\ + while still giving protection against most mistakes\n\ + --interactive[=WHEN] prompt according to WHEN: never, once (-I), or\n\ + always (-i). Without WHEN, prompt always\n\ "), stdout); fputs (_("\ --no-preserve-root do not treat `/' specially (the default)\n\ @@ -161,7 +191,7 @@ use one of these commands:\n\ \n\ %s ./-foo\n\ "), - base, base); + program_name, program_name); fputs (_("\ \n\ Note that if you use rm to remove a file, it is usually possible to recover\n\ @@ -193,6 +223,7 @@ main (int argc, char **argv) { bool preserve_root = false; struct rm_options x; + bool prompt_once = false; int c; initialize_main (&argc, &argv); @@ -205,7 +236,7 @@ main (int argc, char **argv) rm_option_init (&x); - while ((c = getopt_long (argc, argv, "dfirvR", long_opts, NULL)) != -1) + while ((c = getopt_long (argc, argv, "dfirvIR", long_opts, NULL)) != -1) { switch (c) { @@ -219,11 +250,19 @@ main (int argc, char **argv) case 'f': x.interactive = false; x.ignore_missing_files = true; + prompt_once = false; break; case 'i': x.interactive = true; x.ignore_missing_files = false; + prompt_once = false; + break; + + case 'I': + x.interactive = false; + x.ignore_missing_files = false; + prompt_once = true; break; case 'r': @@ -231,6 +270,36 @@ main (int argc, char **argv) x.recursive = true; break; + case INTERACTIVE_OPTION: + { + int i; + if (optarg) + i = XARGMATCH ("--interactive", optarg, interactive_args, + interactive_types); + else + i = interactive_always; + switch (i) + { + case interactive_never: + x.interactive = false; + prompt_once = false; + break; + + case interactive_once: + x.interactive = false; + x.ignore_missing_files = false; + prompt_once = true; + break; + + case interactive_always: + x.interactive = true; + x.ignore_missing_files = false; + prompt_once = false; + break; + } + break; + } + case NO_PRESERVE_ROOT: preserve_root = false; break; @@ -279,6 +348,16 @@ main (int argc, char **argv) size_t n_files = argc - optind; char const *const *file = (char const *const *) argv + optind; + if (prompt_once && (x.recursive || 3 < n_files)) + { + fprintf (stderr, + (x.recursive + ? _("%s: remove all arguments recursively? ") + : _("%s: remove all arguments? ")), + program_name); + if (!yesno ()) + exit (EXIT_SUCCESS); + } enum RM_status status = rm (n_files, file, &x); assert (VALID_STATUS (status)); exit (status == RM_ERROR ? EXIT_FAILURE : EXIT_SUCCESS); Index: tests/rm/Makefile.am =================================================================== RCS file: /sources/coreutils/coreutils/tests/rm/Makefile.am,v retrieving revision 1.32 diff -u -p -r1.32 Makefile.am --- tests/rm/Makefile.am 11 Feb 2006 18:03:52 -0000 1.32 +++ tests/rm/Makefile.am 18 Feb 2006 17:46:52 -0000 @@ -13,6 +13,7 @@ TESTS = \ cycle i-no-r fail-eperm \ dangling-symlink rm1 rm2 rm3 rm4 rm5 \ unread2 r-1 r-2 r-3 i-1 ir-1 f-1 sunos-1 deep-1 hash \ + interactive-always interactive-once \ isatty # unreadable empty-name EXTRA_DIST = $(TESTS) TESTS_ENVIRONMENT = \ Index: tests/rm/interactive-once =================================================================== RCS file: tests/rm/interactive-once diff -N tests/rm/interactive-once --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ tests/rm/interactive-once 18 Feb 2006 17:46:52 -0000 @@ -0,0 +1,116 @@ +#!/bin/sh +# Test the -I option added to coreutils 6.0 + +test=interactive-once + +if test "$VERBOSE" = yes; then + set -x + rm --version +fi + +. $srcdir/../lang-default + +pwd=`pwd` +t0=`echo "$0"|sed 's,.*/,,'`.tmp; tmp=$t0/$$ +trap 'status=$?; cd $pwd; chmod -R u+rwx $t0; rm -rf $t0 && exit $status' 0 +trap '(exit $?); exit $?' 1 2 13 15 + +framework_failure=0 +mkdir -p $tmp || framework_failure=1 +cd $tmp || framework_failure=1 + +mkdir -p dir1-1 dir2-1 dir2-2 || framework_failure=1 +touch file1-1 file2-1 file2-2 file2-3 file3-1 file3-2 file3-3 file3-4 \ + || framework_failure=1 +echo y > $test.Iy || framework_failure=1 +echo n > $test.In || framework_failure=1 +rm -f out err || framework_failure=1 + +if test $framework_failure = 1; then + echo "$0: failure in testing framework" 1>&2 + (exit 1); exit 1 +fi + +fail=0 + +# The prompt has a trailing space, and no newline, so an extra +# 'echo .' is inserted after each rm to make it obvious what was asked. + +echo 'one file, no recursion' > err || fail=1 +rm -I file1-* < $test.In >> out 2>> err || fail=1 +echo . >> err || fail=1 +test -f file1-1 && fail=1 + +echo 'three files, no recursion' >> err || fail=1 +rm -I file2-* < $test.In >> out 2>> err || fail=1 +echo . >> err || fail=1 +test -f file2-1 && fail=1 +test -f file2-2 && fail=1 +test -f file2-3 && fail=1 + +echo 'four files, no recursion, answer no' >> err || fail=1 +rm -I file3-* < $test.In >> out 2>> err || fail=1 +echo . >> err || fail=1 +test -f file3-1 || fail=1 +test -f file3-2 || fail=1 +test -f file3-3 || fail=1 +test -f file3-4 || fail=1 + +echo 'four files, no recursion, answer yes' >> err || fail=1 +rm -I file3-* < $test.Iy >> out 2>> err || fail=1 +echo . >> err || fail=1 +test -f file3-1 && fail=1 +test -f file3-2 && fail=1 +test -f file3-3 && fail=1 +test -f file3-4 && fail=1 + +echo 'one file, recursion, answer no' >> err || fail=1 +rm -I -R dir1-* < $test.In >> out 2>> err || fail=1 +echo . >> err || fail=1 +test -d dir1-1 || fail=1 + +echo 'one file, recursion, answer yes' >> err || fail=1 +rm -I -R dir1-* < $test.Iy >> out 2>> err || fail=1 +echo . >> err || fail=1 +test -d dir1-1 && fail=1 + +echo 'multiple files, recursion, answer no' >> err || fail=1 +rm -I -R dir2-* < $test.In >> out 2>> err || fail=1 +echo . >> err || fail=1 +test -d dir2-1 || fail=1 +test -d dir2-2 || fail=1 + +echo 'multiple files, recursion, answer yes' >> err || fail=1 +rm -I -R dir2-* < $test.Iy >> out 2>> err || fail=1 +echo . >> err || fail=1 +test -d dir2-1 && fail=1 +test -d dir2-2 && fail=1 + +cat <<\EOF > expout || fail=1 +EOF +cat <<\EOF > experr || fail=1 +one file, no recursion +. +three files, no recursion +. +four files, no recursion, answer no +rm: remove all arguments? . +four files, no recursion, answer yes +rm: remove all arguments? . +one file, recursion, answer no +rm: remove all arguments recursively? . +one file, recursion, answer yes +rm: remove all arguments recursively? . +multiple files, recursion, answer no +rm: remove all arguments recursively? . +multiple files, recursion, answer yes +rm: remove all arguments recursively? . +EOF + +cmp out expout || fail=1 +cmp err experr || fail=1 +test $fail = 1 && { + diff out expout 2> /dev/null; diff err experr 2> /dev/null +} + +(exit $fail); exit $fail Index: tests/rm/interactive-always =================================================================== RCS file: tests/rm/interactive-always diff -N tests/rm/interactive-always --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ tests/rm/interactive-always 18 Feb 2006 17:46:52 -0000 @@ -0,0 +1,96 @@ +#!/bin/sh +# Test the --interactive[=WHEN] changes added to coreutils 6.0 + +test=interactive-always + +if test "$VERBOSE" = yes; then + set -x + rm --version +fi + +. $srcdir/../lang-default + +pwd=`pwd` +t0=`echo "$0"|sed 's,.*/,,'`.tmp; tmp=$t0/$$ +trap 'status=$?; cd $pwd; chmod -R u+rwx $t0; rm -rf $t0 && exit $status' 0 +trap '(exit $?); exit $?' 1 2 13 15 + +framework_failure=0 +mkdir -p $tmp || framework_failure=1 +cd $tmp || framework_failure=1 + +touch file1-1 file1-2 file2-1 file2-2 file3-1 file3-2 file4-1 file4-2 \ + || framework_failure=1 +# If asked, answer no to first question, then yes to second. +echo 'n +y' > $test.I || framework_failure=1 +rm -f out err || framework_failure=1 + +if test $framework_failure = 1; then + echo "$0: failure in testing framework" 1>&2 + (exit 1); exit 1 +fi + +fail=0 + +# The prompt has a trailing space, and no newline, so an extra +# 'echo .' is inserted after each rm to make it obvious what was asked. + +echo 'no WHEN' > err || fail=1 +rm -R --interactive file1-* < $test.I >> out 2>> err || fail=1 +echo . >> err || fail=1 +test -f file1-1 || fail=1 +test -f file1-2 && fail=1 + +echo 'WHEN=never' >> err || fail=1 +rm -R --interactive=never file2-* < $test.I >> out 2>> err || fail=1 +echo . >> err || fail=1 +test -f file2-1 && fail=1 +test -f file2-2 && fail=1 + +echo 'WHEN=once' >> err || fail=1 +rm -R --interactive=once file3-* < $test.I >> out 2>> err || fail=1 +echo . >> err || fail=1 +test -f file3-1 || fail=1 +test -f file3-2 || fail=1 + +echo 'WHEN=always' >> err || fail=1 +rm -R --interactive=always file4-* < $test.I >> out 2>> err || fail=1 +echo . >> err || fail=1 +test -f file4-1 || fail=1 +test -f file4-2 && fail=1 + +echo '-f overrides --interactive' >> err || fail=1 +rm -R --interactive=once -f file1-* < $test.I >> out 2>> err || fail=1 +echo . >> err || fail=1 +test -f file1-1 && fail=1 + +echo '--interactive overrides -f' >> err || fail=1 +rm -R -f --interactive=once file4-* < $test.I >> out 2>> err || fail=1 +echo . >> err || fail=1 +test -f file4-1 || fail=1 + +cat <<\EOF > expout || fail=1 +EOF +cat <<\EOF > experr || fail=1 +no WHEN +rm: remove regular empty file `file1-1'? rm: remove regular empty file `file1-2'? . +WHEN=never +. +WHEN=once +rm: remove all arguments recursively? . +WHEN=always +rm: remove regular empty file `file4-1'? rm: remove regular empty file `file4-2'? . +-f overrides --interactive +. +--interactive overrides -f +rm: remove all arguments recursively? . +EOF + +cmp out expout || fail=1 +cmp err experr || fail=1 +test $fail = 1 && { + diff out expout 2> /dev/null; diff err experr 2> /dev/null +} + +(exit $fail); exit $fail Index: doc/coreutils.texi =================================================================== RCS file: /sources/coreutils/coreutils/doc/coreutils.texi,v retrieving revision 1.311 diff -u -p -r1.311 coreutils.texi --- doc/coreutils.texi 12 Feb 2006 08:48:42 -0000 1.311 +++ doc/coreutils.texi 18 Feb 2006 17:46:54 -0000 @@ -7327,10 +7327,16 @@ rm [EMAIL PROTECTED]@dots{} [EMAIL PROTECTED]@do @end example @cindex prompting, and @command{rm} -If a file is unwritable, standard input is a terminal, and the @option{-f} -or @option{--force} option is not given, or the @option{-i} or [EMAIL PROTECTED] option @emph{is} given, @command{rm} prompts the user -for whether to remove the file. +If the @option{-I} or @option{--interactive=once} option is given, +and there are more than three files or the @option{-r}, @option{-R}, +or @option{--recursive} are given, then @command{rm} prompts the user +for whether to proceed with the entire operation. If the response is +not affirmitive, the entire command is aborted. + +Otherwise, if a file is unwritable, standard input is a terminal, and +the @option{-f} or @option{--force} option is not given, or the [EMAIL PROTECTED] or @option{--interactive=always} option @emph{is} given, [EMAIL PROTECTED] prompts the user for whether to remove the file. If the response is not affirmative, the file is skipped. @emph{Warning}: If you use @command{rm} to remove a file, it is usually @@ -7349,12 +7355,37 @@ Ignore nonexistent files and never promp Ignore any previous @option{--interactive} (@option{-i}) option. @item -i [EMAIL PROTECTED] --interactive @opindex -i [EMAIL PROTECTED] --interactive Prompt whether to remove each file. If the response is not affirmative, the file is skipped. Ignore any previous @option{--force} (@option{-f}) option. +Equivalent to @option{--interactive=always}. + [EMAIL PROTECTED] -I [EMAIL PROTECTED] -I +Prompt once whether to proceed with the command, if more than three +files are named or if a recursive removal is requested. Ignore any +previous @option{--force} (@option{-f}) option. Equivalent to [EMAIL PROTECTED] + [EMAIL PROTECTED] --interactive [EMAIL PROTECTED] [EMAIL PROTECTED] --interactive +Specify when to issue an interactive prompt. @var{when} may be +omitted, or one of: [EMAIL PROTECTED] @bullet [EMAIL PROTECTED] never [EMAIL PROTECTED] never @r{interactive option} +- Do not prompt at all. [EMAIL PROTECTED] once [EMAIL PROTECTED] once @r{interactive option} +- Prompt once if more than three files are named or if a recursive +removal is requested. Equivalent to @option{-I}. [EMAIL PROTECTED] always [EMAIL PROTECTED] always @r{interactive option} +- Prompt for every file being removed. Equivalent to @option{-i}. [EMAIL PROTECTED] itemize +Specifying @option{--interactive} and no @var{when} is equivalent to [EMAIL PROTECTED] @itemx --preserve-root @opindex --preserve-root
_______________________________________________ Bug-coreutils mailing list Bug-coreutils@gnu.org http://lists.gnu.org/mailman/listinfo/bug-coreutils