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)?

6 Answers 6

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
2
  • Using the wildcard for this purpose won't work if there are a lot of entries in that directory. unix.stackexchange.com/a/712128/353102 is a better solution.
    – user582175
    Mar 31, 2023 at 7: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, 2023 at 17:54
6
find inner -mindepth 1 -delete
3
  • 1
    Welcome to the site, and thank you for your contribution. Please note that brevity is acceptable, but fuller explanations are better. You may want to add a note why you think this approach will solve the OPs problem.
    – AdminBee
    Aug 2, 2022 at 12:47
  • … and explain, if you can,  why you believe that this answer is better than the previous answers featuring find. Aug 2, 2022 at 17:00
  • @G-ManSays'ReinstateMonica' 1. It deletes not only files but directories too. 2. It doesn't require to specify inner directory name twice. 3. Compared to rm with glob it removes dot files too, it doesn't fail with "Argument list too long" on big list of files.
    – dimich
    Aug 2, 2022 at 17:51
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.

1
  • Simple and effective solution. I use it when deleting in /var/log directory Nov 10, 2021 at 11:51
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.

2
  • Note that -delete comes from BSDs, not GNU initially IIRC. May 4, 2022 at 11:42
  • -path is not documented for AIX's (primitive) find command, but appears to work anyway. You could also cd to inner and then use find . -depth ! -name . -exec rm -r {} +
    – jrw32982
    May 9, 2022 at 20:25
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
2
  • 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, 2023 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, 2023 at 7: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)

6
  • 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 4, 2022 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. May 4, 2022 at 11:41
  • @StéphaneChazelas I'm away from computers at the moment, but I'll take your word for it.
    – Kusalananda
    May 4, 2022 at 12:08
  • @Kusalananda Sorry for not considering this. How about ls -A | xargs -I {} rm -r "{}"?
    – searchstar
    May 6, 2022 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 6, 2022 at 11:11

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .