Bash script to remove all files and directories except specific ones

懵懂的女人 提交于 2019-11-30 18:34:14

Two problems I can see right off the bat:

  • The -rf argument to rm must come before the filenames
  • The extglob specifiers !, (, | and ) should not be escaped with backslashes

Try this instead:

rm -rf !(filename1|filename2|filename3)

If it's still not working, remove the -f argument, and you'll get error messages about what's going wrong instead of silently suppressing them. To print out the name of each file removed, you can add the -v option as well.

If you have a recent version of find, then use:

find . -not -regex "filename1|filename2|filename3" -print

Check the output and replace -print with -delete if it prints only the files that you really want to delete.

If your version of find doesn't support -delete, use -type f -exec rm "{}" \;

Note that this will only delete files. This is important: If you say to keep file x but that file is in a folder y, then it would ignore x only to delete it later with the whole folder y.

To get rid of all empty folders (and this preserving the files you want to keep):

find . -type d -empty -exec rmdir "{}" \;

(source: How to Find and Delete Empty Directories and Files in Unix)

I don't recommend trying to write a rule to exempt specific files. What I would be more likely to do, would be to try and find either a filemask/glob, or some other anchor in the names of the files that you do want to remove, which the files you want to keep, does not have. In most cases, you could probably do that by extension. Unfortunately, because you haven't mentioned what the names of any of the files are, I can't help you more specifically.

Something like two (or more) find loops:-

find *.mp3 d.mp3 -maxdepth 1 -type f | while read mp3s
do
mv $mp3s ~/d.stuff-to-keep
done    

find *.txt d.mp3 -maxdepth 1 -type f while read textfiles
do
rm -v $textfiles
done

If not, look for some other common characteristic of the files. If there isn't one, you might need to rename your files to give yourself one. I always put lots of anchors (seperated name fields, extensions etc) in my filenames, because that way I have a lot of different ways for doing what I need with them. My usual name format is:-

<extension>.+<author>+<year>+<work-name>+<volume-number>+<number-of-volumes>

Plus signs are field seperators, dashes are for spaces, but with no dashes as either first or last characters. All lowercase letters, and no control characters or other non-alphanumerics allowed. As a result, I can cut those up with awk, cut, or whatever else I might want to use, and rename them easily. Putting the extension at the start of the name, also means that ls only needs one flag (-l) to get a perfectly ordered file system.

If you know how to use your directory structure as a database with the basic POSIX tools, you sometimes won't need to install anything more complicated, in order to do what you want.

You've got a long char limit on filenames in UNIX, as well as tab completion for navigating around long names. Don't be afraid to make liberal use of both of them.

Try below:

for i in `ls | grep -v "file1\|file2\|file3"` ; do rm -rf $i; done

Good Luck!

assuming you have files:

drwxr-xr-x 2 root root 4096 Feb 1 02:17 a

drwxr-xr-x 2 root root 4096 Feb 1 02:17 b

drwxr-xr-x 2 root root 4096 Feb 1 02:17 c

drwxr-xr-x 2 root root 4096 Feb 1 02:17 d

drwxr-xr-x 2 root root 4096 Feb 1 02:17 e

drwxr-xr-x 2 root root 4096 Feb 1 02:17 f

drwxr-xr-x 2 root root 4096 Feb 1 02:18 nodelete1

drwxr-xr-x 2 root root 4096 Feb 1 02:18 nodelete2

You could do:

ls | grep -v "nodel.\+" | xargs rm -rf

to use advanced regexp syntax to exclude files.

Explanation:

ls --- lists current directory (ls -d to list only directories)

grep -v --- v flag specifies what NOT TO MATCH + grep allows to write perl style regexp if you supply -P flag

xargs --- applies action "rm -rf" on each of the items

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!