9

I have a directory called outer.

outer contains a directory named inner (which contains lots of files of same extension)

I cd to outer. How can I delete all the files within inner but leave the directory inner remaining (but empty)?

user997112
  • 1,015

6 Answers6

12

If you want to delete a directory's contents and not the directory itself, all you need to do is tell rm to delete the contents:

rm inner/*

That will delete all non-hidden files in ./inner and leave the directory intact. To also delete any subdirectories, use -r:

rm -r inner/*

If you also want to delete hidden files, you can do (assuming you are using bash):

shopt -s dotglob
rm -r inner/*

That last command will delete all files and all directories in inner, but will leave inner itself intact.

Finally, note that you don't need to cd to outer to run any of these:

$ tree -a outer/
outer/
├── dir
└── inner
    ├── dir
    ├── file
    └── .hidden

3 directories, 2 files

I can now run rm -r outer/inner/* from my current directory, no need to cd outer, and it will remove everything except the directory itself:

$ shopt -s dotglob
$ rm -r outer/inner/*
$ tree -a outer/
outer/
├── dir
└── inner

2 directories, 0 files
terdon
  • 242,166
  • Using the wildcard for this purpose won't work if there are a lot of entries in that directory. https://unix.stackexchange.com/a/712128/353102 is a better solution. – user582175 Mar 31 '23 at 07:25
  • @user582175 only if you have hundreds of thousands of files there, and only if you are using GNU find since the delete option isn't portable. But yes, if both those things are true, you need workarounds like that find command. – terdon Mar 31 '23 at 17:54
6
find inner -mindepth 1 -delete
AdminBee
  • 22,803
dimich
  • 416
4

If you want to delete all files under some directory structure, but keep all directories, the easiest is to use find's -delete switch:

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

To first check what would be deleted, just leave out the -delete at the end.

mivk
  • 3,596
1
find inner ! -path inner -delete

This would traverse the inner directory and delete everything. The ! -path inner test makes sure that the inner directory itself is not deleted (but all its contents is deleted).

The above would work on Linux with GNU find (the default find). The -delete action is however non-standard (albeit commonly implemented). For a standard compliant variation, use

find inner -depth ! -path inner -exec rm -r {} +

The -depth option makes sure that find does a depth-first traversal of the directory structure. Without this, you may end up trying to delete directories before they are empty.

terdon
  • 242,166
Kusalananda
  • 333,661
0

I use this loop alot, this way you can apply to any number of folders, don't even need to wory!

for i in `ls`; do rm -f $i/*; done
Marc
  • 1
  • Welcome to the site. Please note that this approach is prone to stumbling upon directory names with special characters (in particular, spaces), see this answer for further reading. Also, it will unnecessarily iterate over files in the current directory and try to delete their "directory content". – AdminBee Apr 20 '23 at 14:25
  • 1
    Indeed, it doesn't work with files that have a space in the name. Thanks for the link, it's very helpful! I was trying to find a simple one-liner solution. I even though about working with inodes but it would not be cleaner than the answers given here. Thanks for the help and the welcome :) – Marc Apr 27 '23 at 07:13
-2

How about this?

cd inner
ls -A | xargs -I {} rm -r "{}"

Edit: DO NOT USE. This has security issues if the filename contains quotes or newlines. (Code injections for example)

  • 2
    This does not handle names with spaces or quotes. I believe it may misbehave and delete files outside of the top directory if given specially crafted filenames. – Kusalananda May 04 '22 at 11:17
  • @Kusalananda, backslashes and filenames starting with - would also be a problem, however, I don't think it could delete files outside the top directory. xargs may end up passing .. as one argument to rm, however rm implementations are meant to reject those. – Stéphane Chazelas May 04 '22 at 11:41
  • @StéphaneChazelas I'm away from computers at the moment, but I'll take your word for it. – Kusalananda May 04 '22 at 12:08
  • @Kusalananda Sorry for not considering this. How about ls -A | xargs -I {} rm -r "{}"? – searchstar May 06 '22 at 10:33
  • @searchstar You can test your solution on files created in these ways: touch '"hello world"' (filename containing quotes), and touch $'hello\nworld' (filename containing newline). – Kusalananda May 06 '22 at 11:11
  • I see. Thank you very much. The issues really shock me. – searchstar May 06 '22 at 14:28