In BASH you can use the trailing slash (I think it should work in any POSIX shell):
rm -R -- */
Note the --
which separates options from arguments and allows one to remove entries starting with a hyphen - otherwise after expansion by the shell the entry name would be interpreted as an option by rm
(the same holds for many other command line utilities).
Add the -f
option if you don't want to be prompted for confirmation when deleting non-writeable files.
Note that by default, hidden directories (those whose name starts with .
) will be left alone.
An important caveat: the expansion of */
will also include symlinks that eventually resolve to files of type directory. And depending on the rm
implementation, rm -R -- thelink/
will either just delete the symlink, or (in most of them) delete the content of the linked directory recursively but not that directory itself nor the symlink.
If using zsh
, a better approach would be to use a glob qualifier to select files of type directory only:
rm -R -- *(/) # or *(D/) to include hidden ones
or:
rm -R -- *(-/)
to include symlinks to directories (but because, this time, the expansion doesn't have trailing /
s, it's the symlink only that is removed with all rm
implementations).
With bash
, AT&T ksh
, yash
or zsh
you can do:
set -- */
rm -R -- "${@%/}"
to strip the trailing /
.
You don't get a warning in bash
, you get an error by ls
(you'll find that ls
exit status is non-0 which indicates it has failed).
In both zsh
and bash
, {...}
is not a globbing operator, it's an expansion that occurs before globbing.
In:
ls -d -- *.{dot,svg,err}
(you forgot the -d
and --
btw), the shell expands the {...}
first:
ls -d -- *.dot *.svg *.err
and then does the glob. bash
like most Bourne-like shells has that misfeature that non-matching globs are passed as-is. While on zsh
, a non-matching glob is an error.
See how rm -f [ab].c
in bash
could delete the [ab].c
file if there was no file called a.c
nor b.c
. In zsh
, you'd get a no match error instead. See the failglob
option in bash
to get a similar behaviour.
ls -d -- *.{dot,svg,err}(N)
in zsh
would enable the nullglob
option on all 3 globs, so that if the globs don't match, they are removed, but that's probably not what you want, because if none of the globs match any file, the command will become:
ls -d --
Which will list .
(the current directory) instead.
Best here is to use one glob that matches files with either of the 3 extensions:
ls -d -- *.(dot|svg|err)
That will give a sorted list of files to ls
, ls
will be run unless there's no file found matching that one pattern.
You also have the option to enable the sh
/bash
(bogus IMO) behaviour with emulate sh
or with unsetopt nomatch
. A slightly better approach is to enable the csh
behaviour (which was also the behaviour of Unix shells before the Bourne shell was released):
setopt cshnullglob
With that option, the command is cancelled only if all the globs on the command line fail to match. If at least one matches, all the ones that don't match are removed so:
ls -d -- *.{dot,svg,err}
Will expand the dot
, svg
and err
in turn, omitting the missing ones.
If you want to compare the effect on the order of the arguments of the different approaches, you need a command that (contrary to ls
) doesn't sort them before displaying. With GNU ls
, you can pass the -U
option for that, or since ls
does only print its arguments here, just use printf '%s\n' *...
instead.
Best Answer
You could always send error messages to
/dev/null
You could also just
...then you won't have to bother with hidden files in the first place.