On Thu, Nov 21, 2013 at 8:18 AM, Bernhard Voelker <m...@bernhard-voelker.de> wrote: > On 11/21/2013 04:06 PM, Eric Blake wrote: >> >> Hard to say that it is considerable bloat without seeing a patch; we >> already know when the top-level arguments are directories thanks to 'rm >> -d'. > > > Here's a draft - not tested more than this: > > $ mkdir -p /tmp/dir /tmp/dir/sub > $ touch /tmp/dir/file /tmp/dir/sub/other > > $ src/rm -rv --child /tmp/dir > removed ‘/tmp/dir/file’ > removed ‘/tmp/dir/sub/other’ > removed directory: ‘/tmp/dir/sub’ > src/rm: skipping ‘/tmp/dir’, due to --children-only > > $ src/rm -rv --child /tmp/dir > src/rm: skipping ‘/tmp/dir’, due to --children-only > > $ src/rm -rv --child /tmp/dir/. > src/rm: skipping ‘/tmp/dir/.’, due to --children-only > > > Have a nice day, > Berny > > From 03d58cc281c6155d50be9b770bbac7bf73cdaf92 Mon Sep 17 00:00:00 2001 > From: Bernhard Voelker <m...@bernhard-voelker.de> > Date: Thu, 21 Nov 2013 17:11:27 +0100 > Subject: [PATCH] rm: add --children-only option > > FIXME > --- > src/mv.c | 1 + > src/remove.c | 29 ++++++++++++++++++++++++----- > src/remove.h | 4 ++++ > src/rm.c | 9 +++++++++ > 4 files changed, 38 insertions(+), 5 deletions(-) > > diff --git a/src/mv.c b/src/mv.c > index 1cfcd82..36e70a4 100644 > --- a/src/mv.c > +++ b/src/mv.c > @@ -74,6 +74,7 @@ rm_option_init (struct rm_options *x) > { > x->ignore_missing_files = false; > x->remove_empty_directories = true; > + x->children_only = false; > x->recursive = true; > x->one_file_system = false; > > diff --git a/src/remove.c b/src/remove.c > index 3d386cf..eb05cb4 100644 > --- a/src/remove.c > +++ b/src/remove.c > @@ -439,8 +439,10 @@ rm_fts (FTS *fts, FTSENT *ent, struct rm_options const > *x) > { > > /* POSIX says: > If the basename of a command line argument is "." or "..", > - diagnose it and do nothing more with that argument. */ > - if (dot_or_dotdot (last_component (ent->fts_accpath))) > + diagnose it and do nothing more with that argument. > + FIXME: mention --children-only. */ > + if (! x->children_only > + && dot_or_dotdot (last_component (ent->fts_accpath))) > { > error (0, 0, > > _("refusing to remove %s or %s directory: skipping > %s"), > @@ -468,9 +470,17 @@ rm_fts (FTS *fts, FTSENT *ent, struct rm_options const > *x) > > if (s == RM_OK && is_empty_directory == T_YES) > { > - /* When we know (from prompt when in interactive mode) > - that this is an empty directory, don't prompt twice. */ > - s = excise (fts, ent, x, true); > + if (FTS_ROOTLEVEL == ent->fts_level && x->children_only) > + { > + error (0, 0, _("skipping %s, due to --children-only"), > + quote (ent->fts_path)); > + } > + else > + { > + /* When we know (from prompt when in interactive mode) > + that this is an empty directory, don't prompt twice. */ > + s = excise (fts, ent, x, true); > + } > fts_skip_tree (fts, ent); > } > > @@ -492,6 +502,15 @@ rm_fts (FTS *fts, FTSENT *ent, struct rm_options const > *x) > case FTS_NSOK: /* e.g., dangling symlink */ > case FTS_DEFAULT: /* none of the above */ > { > + if (ent->fts_info == FTS_DP > + && x->children_only > + && FTS_ROOTLEVEL == ent->fts_level) > + { > + mark_ancestor_dirs (ent); > + error (0, 0, _("skipping %s, due to --children-only"), > + quote (ent->fts_path)); > + return RM_OK; > + } > /* With --one-file-system, do not attempt to remove a mount point. > fts' FTS_XDEV ensures that we don't process any entries under > the mount point. */ > diff --git a/src/remove.h b/src/remove.h > index 9ac54d4..248a470 100644 > --- a/src/remove.h > +++ b/src/remove.h > @@ -52,6 +52,10 @@ struct rm_options > /* If true, remove empty directories. */ > bool remove_empty_directories; > > + /* If true (and the -r option is also specified), remove all children > + of directory arguments, yet retaining the directory itself. */ > + bool children_only; > + > /* Pointer to the device and inode numbers of '/', when --recursive > and preserving '/'. Otherwise NULL. */ > struct dev_ino *root_dev_ino; > diff --git a/src/rm.c b/src/rm.c > index 7a51eef..0634855 100644 > --- a/src/rm.c > +++ b/src/rm.c > @@ -51,6 +51,7 @@ enum > ONE_FILE_SYSTEM, > NO_PRESERVE_ROOT, > PRESERVE_ROOT, > + CHILDREN_ONLY, > PRESUME_INPUT_TTY_OPTION > }; > > @@ -78,6 +79,7 @@ static struct option const long_opts[] = > > {"recursive", no_argument, NULL, 'r'}, > {"dir", no_argument, NULL, 'd'}, > + {"children-only", no_argument, NULL, CHILDREN_ONLY}, > {"verbose", no_argument, NULL, 'v'}, > {GETOPT_HELP_OPTION_DECL}, > {GETOPT_VERSION_OPTION_DECL}, > @@ -156,6 +158,8 @@ Remove (unlink) the FILE(s).\n\ > --preserve-root do not remove '/' (default)\n\ > -r, -R, --recursive remove directories and their contents > recursively\n\ > -d, --dir remove empty directories\n\ > + --children-only remove only children, yet retaining the given\n\ > + directory arguments\n\ ...
Thanks for the quick work. What do you think about saying something simple yet imprecise in --help, like "when recursive, suppress removal of any directory named on the command line" with the caveat that the texinfo doc would add precision: but a command-line-specified directory may still end up being removed when it is also a subdirectory of another command line argument.