toop
toop

Reputation: 11294

Remove all files in a directory (do not touch any folders or anything within them)

I would like to know whether rm can remove all files within a directory (but not the subfolders or files within the subfolders)?

I know some people use:

rm -f /direcname/*.*

but this assumes the filename has an extension which not all do (I want all files - with or without an extension to be removed).

Upvotes: 18

Views: 38071

Answers (8)

Jon R
Jon R

Reputation: 317

The easiest way to do this is to use:

rm *

In order to remove directories, you must specify the option -r

rm -r

so your directories and anything contained in them will not be removed by using

rm *

per the man page for rm, its purpose is to remove files, which is why this works

Upvotes: 1

David W.
David W.

Reputation: 107040

I would like to know whether rm can remove all files within a directory (but not the subfolders or files within the subfolders)?

That's easy:

$ rm folder/*

Without the -r, the rm command won't touch sub-directories or the files they contain. This will only remove the files in folder and not the sub-directories or their files.

You will see errors telling you that folder/foo is a directory can cannot be removed, but that's actually okay with you. If you want to eliminate these messages, just redirect STDERR:

$ rm folder/* 2> /dev/null

By the way, the exit status of the rm command may not be zero, so you can't check rm for errors. If that's important, you'll have to loop:

$ for file in *
> do
> [[ -f $file ]] && rm $file
> [[ $? -ne 0 ]] && echo "Error in removing file '$file'"
> done

This should work in BASH even if the file names have spaces in them.

Upvotes: 3

troller
troller

Reputation: 461

Although find allows you to delete files using -exec rm {} \; you can use

find /direcname -maxdepth 1 -type f -delete

and it is faster. Using -delete implies the -depth option, which means process directory contents before directory.

Upvotes: 36

Kaz
Kaz

Reputation: 58578

Unix isn't DOS. There is no special "extension" field in a file name. Any characters after a dot are just part of the name and are called the suffix. There can be more than one suffix, for example.tar.gz. The shell glob character * matches across the . character; it is oblivious to suffixes. So the MS-DOS *.* is just * In Unix.

Almost. * does not match files which start with a .. Objects named with a leading dot are, by convention, "hidden". They do not show up in ls either unless you specify -a.

(This means that the . and .. directory entries for "self" and "parent" are considered hidden.)

To match hidden entries also, use .*

The rm command does not remove directories (when not operated recursively with -r). Try rm <directory> and see. Even if the directory is empty, it will refuse.

So, the way you remove all (non-hidden) files, pipes, devices, sockets and symbolic links from a directory (but leave the subdirectories alone) is in fact:

rm /path/to/directory/*

to also remove the hidden ones which start with .:

rm /path/to/directory/{*,.*}

This syntax is brace expansion. Brace expansion is not pattern matching; it is just a short-hand for generating multiple arguments, in this case:

rm /path/to/directory/* /path/to/directory/.*

this expansion takes place first first and then globbing takes place to generate the names to be deleted.

Note that various solutions posted here have various issues:

find /path/to/directory -type f -delete

# -delete is not Unix standard; GNU find extension
# without -maxdepth 1 this will recurse over all files
# -maxdepth is also a GNU extension
# -type f finds only files; so this neglects to delete symlinks, fifos, etc.

The GNU find solutions have the benefit that they work even if the number of directory entries to be deleted is huge: too large to pass in a single call to rm. Another benefit is that the built-in -delete does not have issues with passing funny path names to an external command.

The portable workaround for the problem of too many directory entries is to list the entries with ls and pipe to xargs:

( cd /path/to/directory ; ls -a | xargs rm -- )

The parentheses mean "do these commands in a sub-process"; this way the effect of the cd is forgotten, which is useful in scripting. ls -a includes the hidden files.

We now include a -- after rm which means "this is the last option; everything else is a non-option argument". This guards us against directory entries whose names are indistinguishable from options. What if a file is called -rf and ends up the first argument? Then you have rm -rf ... which will blow off subdirectories.

Upvotes: 1

Some shells, notably zsh and perhaps bash version 4 (but not version 3), have a syntax to do that.

With zsh you might just type

rm /dir/path/*(.)

and if you would want to remove any file whose name starts with foo, recursively in subdirectories, you could do

rm /dir/path/**/foo*(.)

the double star feature is (with IMHO better interactive completion) in my opinion enough to switch to zsh for interactive shells. YMMV

The dot in parenthesis suffix indicates that you want only files (not symlinks or directories) to be expanded by the zsh shell.

Upvotes: 1

huon
huon

Reputation: 102066

find /direcname -maxdepth 1 -type f -exec rm {} \;

Explanation:

  • find searches for files and directories within /direcname
  • -maxdepth restricts it to looking for files and directories that are direct children of /direcname
  • -type f restricts the search to files
  • -exec rm {} \; runs the command rm {} for each file (after substituting the file's path in place of {}).

Upvotes: 8

Jens
Jens

Reputation: 72639

A shell solution (without the non-standard find -maxdepth) would be

for file in .* *; do
   test -f "$file" && rm "$file"
done

Upvotes: 2

tonio
tonio

Reputation: 10541

You can use

find /direcname -maxdepth 1 -type f -exec rm -f {} \;

Upvotes: 2

Related Questions