mirror of
git://git.sv.gnu.org/coreutils.git
synced 2026-02-11 01:42:17 +02:00
rm: new option --dir (-d) to remove empty directories
Add new option to rm (-d/--dir), which allows removal of empty directories, while still safely disallowing removal of non-empty ones. This improves compatibility with Mac OS X and BSD systems, which honor the -d option. * src/remove.c (rm_fts): Remove empty directories when requested. * src/remove.h (rm_options) [remove_empty_directories]: New member. * src/rm.c (long_opts, usage, main): Update usage and option parsing. (rm_option_init): Initialize the new member. * src/mv.c (rm_option_init): Initialize the new member. * tests/rm/d-1: New test case - successfully delete empty dir. * tests/rm/d-2: New test case - refuse to delete nonempty dir. * tests/Makefile.am (TESTS): Add them.
This commit is contained in:
committed by
Jim Meyering
parent
46afefaaa8
commit
fdc2da7165
9
NEWS
9
NEWS
@@ -2,11 +2,20 @@ GNU coreutils NEWS -*- outline -*-
|
||||
|
||||
* Noteworthy changes in release ?.? (????-??-??) [?]
|
||||
|
||||
** Bug fixes
|
||||
|
||||
df now fails when the list of mounted file systems (/etc/mtab) cannot
|
||||
be read, yet the file system type information is needed to process
|
||||
certain options like -a, -l, -t and -x.
|
||||
[This bug was present in "the beginning".]
|
||||
|
||||
** New features
|
||||
|
||||
rm now accepts the --dir (-d) option which makes it remove empty directories.
|
||||
Since removing empty directories is relatively safe, this option can be
|
||||
used as a part of the alias rm='rm --dir'. This improves compatibility
|
||||
with Mac OS X and BSD systems which also honor the -d option.
|
||||
|
||||
|
||||
* Noteworthy changes in release 8.18 (2012-08-12) [stable]
|
||||
|
||||
|
||||
@@ -8807,6 +8807,13 @@ The program accepts the following options. Also see @ref{Common options}.
|
||||
|
||||
@table @samp
|
||||
|
||||
@item -d
|
||||
@itemx --dir
|
||||
@opindex -d
|
||||
@opindex --dir
|
||||
@cindex directories, removing
|
||||
Remove the listed directories if they are empty.
|
||||
|
||||
@item -f
|
||||
@itemx --force
|
||||
@opindex -f
|
||||
|
||||
1
src/mv.c
1
src/mv.c
@@ -73,6 +73,7 @@ static void
|
||||
rm_option_init (struct rm_options *x)
|
||||
{
|
||||
x->ignore_missing_files = false;
|
||||
x->remove_empty_directories = true;
|
||||
x->recursive = true;
|
||||
x->one_file_system = false;
|
||||
|
||||
|
||||
10
src/remove.c
10
src/remove.c
@@ -414,11 +414,15 @@ rm_fts (FTS *fts, FTSENT *ent, struct rm_options const *x)
|
||||
switch (ent->fts_info)
|
||||
{
|
||||
case FTS_D: /* preorder directory */
|
||||
if (! x->recursive)
|
||||
if (! x->recursive
|
||||
&& !(x->remove_empty_directories
|
||||
&& is_empty_dir (fts->fts_cwd_fd, ent->fts_accpath)))
|
||||
{
|
||||
/* This is the first (pre-order) encounter with a directory.
|
||||
/* This is the first (pre-order) encounter with a directory
|
||||
that we can not delete.
|
||||
Not recursive, so arrange to skip contents. */
|
||||
error (0, EISDIR, _("cannot remove %s"), quote (ent->fts_path));
|
||||
int err = x->remove_empty_directories ? ENOTEMPTY : EISDIR;
|
||||
error (0, err, _("cannot remove %s"), quote (ent->fts_path));
|
||||
mark_ancestor_dirs (ent);
|
||||
fts_skip_tree (fts, ent);
|
||||
return RM_ERROR;
|
||||
|
||||
@@ -49,6 +49,9 @@ struct rm_options
|
||||
/* If true, recursively remove directories. */
|
||||
bool recursive;
|
||||
|
||||
/* If true, remove empty directories. */
|
||||
bool remove_empty_directories;
|
||||
|
||||
/* Pointer to the device and inode numbers of '/', when --recursive
|
||||
and preserving '/'. Otherwise NULL. */
|
||||
struct dev_ino *root_dev_ino;
|
||||
|
||||
9
src/rm.c
9
src/rm.c
@@ -77,6 +77,7 @@ static struct option const long_opts[] =
|
||||
{"-presume-input-tty", no_argument, NULL, PRESUME_INPUT_TTY_OPTION},
|
||||
|
||||
{"recursive", no_argument, NULL, 'r'},
|
||||
{"dir", no_argument, NULL, 'd'},
|
||||
{"verbose", no_argument, NULL, 'v'},
|
||||
{GETOPT_HELP_OPTION_DECL},
|
||||
{GETOPT_VERSION_OPTION_DECL},
|
||||
@@ -154,6 +155,7 @@ Remove (unlink) the FILE(s).\n\
|
||||
--no-preserve-root do not treat '/' specially\n\
|
||||
--preserve-root do not remove '/' (default)\n\
|
||||
-r, -R, --recursive remove directories and their contents recursively\n\
|
||||
-d, --dir remove empty directories\n\
|
||||
-v, --verbose explain what is being done\n\
|
||||
"), stdout);
|
||||
fputs (HELP_OPTION_DESCRIPTION, stdout);
|
||||
@@ -189,6 +191,7 @@ rm_option_init (struct rm_options *x)
|
||||
x->ignore_missing_files = false;
|
||||
x->interactive = RMI_SOMETIMES;
|
||||
x->one_file_system = false;
|
||||
x->remove_empty_directories = false;
|
||||
x->recursive = false;
|
||||
x->root_dev_ino = NULL;
|
||||
x->stdin_tty = isatty (STDIN_FILENO);
|
||||
@@ -220,10 +223,14 @@ main (int argc, char **argv)
|
||||
/* Try to disable the ability to unlink a directory. */
|
||||
priv_set_remove_linkdir ();
|
||||
|
||||
while ((c = getopt_long (argc, argv, "firvIR", long_opts, NULL)) != -1)
|
||||
while ((c = getopt_long (argc, argv, "dfirvIR", long_opts, NULL)) != -1)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'd':
|
||||
x.remove_empty_directories = true;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
x.interactive = RMI_NEVER;
|
||||
x.ignore_missing_files = true;
|
||||
|
||||
@@ -98,6 +98,8 @@ TESTS = \
|
||||
chgrp/basic \
|
||||
rm/dangling-symlink \
|
||||
misc/ls-time \
|
||||
rm/d-1 \
|
||||
rm/d-2 \
|
||||
rm/deep-1 \
|
||||
rm/deep-2 \
|
||||
rm/dir-no-w \
|
||||
|
||||
38
tests/rm/d-1
Executable file
38
tests/rm/d-1
Executable file
@@ -0,0 +1,38 @@
|
||||
#!/bin/sh
|
||||
# Test "rm --dir --verbose".
|
||||
|
||||
# Copyright (C) 2012 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
. "${srcdir=.}/init.sh"; path_prepend_ ../src
|
||||
print_ver_ rm
|
||||
|
||||
mkdir a || framework_failure_
|
||||
> b || framework_failure_
|
||||
|
||||
rm --verbose --dir a b > out || fail=1
|
||||
|
||||
cat <<\EOF > exp || framework_failure_
|
||||
removed directory: 'a'
|
||||
removed 'b'
|
||||
EOF
|
||||
|
||||
test -e a && fail=1
|
||||
test -e b && fail=1
|
||||
|
||||
# Compare expected and actual output.
|
||||
compare exp out || fail=1
|
||||
|
||||
Exit $fail
|
||||
33
tests/rm/d-2
Executable file
33
tests/rm/d-2
Executable file
@@ -0,0 +1,33 @@
|
||||
#!/bin/sh
|
||||
# Ensure that 'rm -d dir' (i.e., without --recursive) gives a reasonable
|
||||
# diagnostic when failing.
|
||||
|
||||
# Copyright (C) 2012 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
. "${srcdir=.}/init.sh"; path_prepend_ ../src
|
||||
print_ver_ rm
|
||||
|
||||
mkdir d || framework_failure_
|
||||
> d/a || framework_failure_
|
||||
|
||||
rm -d d 2> out && fail=1
|
||||
printf "%s\n" \
|
||||
"rm: cannot remove 'd': Directory not empty" \
|
||||
> exp || framework_failure_
|
||||
|
||||
compare exp out || fail=1
|
||||
|
||||
Exit $fail
|
||||
Reference in New Issue
Block a user