Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bash script to remove all files and directories except specific ones

Tags:

bash

shell

rm

I am trying to write a very simple Bash shell script that will cd in a specific directory, it will remove all files and directories except some few selected ones and then cd back to the original dir.

My code is:

#!/bin/bash 
cd /path/to/desired/directory
shopt -s extglob
rm !\(filename1\|filename2\|filename3\) -rf
cd -

I have tried many different ways to write the symbols '(' and '|', with single or double quotes or backslash but nothing worked. Note, that shopt -s extgloband rm !(filename1|filename2) -rf work fine outside a script.

Probably I am committing a standard and fundamental bash-scripting error that I cannot see, but experience is to come...

Any suggestions!? Thanks in advance.

like image 220
mariotoss Avatar asked Nov 05 '13 05:11

mariotoss


3 Answers

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.

like image 135
Adam Rosenfield Avatar answered Oct 13 '22 00:10

Adam Rosenfield


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)

like image 41
Aaron Digulla Avatar answered Oct 13 '22 00:10

Aaron Digulla


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.

like image 33
petrus4 Avatar answered Oct 13 '22 00:10

petrus4