4

I wonder if it is possible to specify some elegant condition (parameter maybe?) in rm -rf /folder/* not to delete its subfolders, which contain files with name "dontshoot.txt".

I wasn't able to find any so far.

Thanks in advance for your help!

migrated from stackoverflow.com Jun 13 '13 at 16:43

This question came from our site for professional and enthusiast programmers.

  • 1
    to my knowledge rm cannot exclude patterns, you will have to write a function or script to do this. – Cobra_Fast Jun 13 '13 at 11:50
7

You could simply use find like this

find some_folder ! -name dontshoot.txt -delete

This will delete all files and folders recursively except the dontshoot.txt files. As noted in the other comments it's always helpful to test it without deleting, which can simply be done like this.

find some_folder ! -name dontshoot.txt 

However this will list all folders, even those which contain dontshoot.txt but they won't be deleted as they won't not empty when using -delete.

Edit:

I agree that fedorqui interpretation of the question is more reasonable than mine. To only delete folders that do not contain dontshoot.txt somewhere deep inside their tree structure a terrible inefficient solution would be

find some_folder -type d -exec \
   sh -c "find {} -name dontshoot.txt | grep -q '' || echo rm -fr {}" \;

Explanation:

The outer find command traverses recursively through some_folder finding all directories (-type d) and executing (-exec) the given shell command while replacing {} by the relative path to the found directory.

The find command inside the shell searches the found directories for dontshoot.txt. If it doesn't find anything there will be no output passed on to grep -q '' which therefore will return False and the last part will be executed which will remove the full directory (which does certainly not contain dontshoot.txt) recursively.

In short, it traverses all directories and deletes those who don't contain dontshoot.txt somewhere inside them.

  • I have one doubt: what if we have a folder t/ with dontshoot.txt and otherfile.txt? I think your code would delete the otherfile.txt, although I guess it should not based on the OP. – fedorqui Jun 13 '13 at 13:29
  • Yes you're right, I extended the answer to your more reasonable interpretation of the question. – buergi Jun 13 '13 at 15:14
  • Congrats, this is such a great answer! – fedorqui Jun 14 '13 at 7:58
3

It is not possible to exclude them within rm command.

You can do something like this:

for dir in /folder/*
do
  echo $dir
  if [ ! -f "$dir/dontshoot.txt" ]; then
    rm -rf "$dir"
   fi
done

Important:

Check it with ls instead of rm before executing.

  • I got upvoted and downvoted at the same time! – fedorqui Jun 13 '13 at 11:55
  • 1
    That's not me, I swear! ;D Thanks for reply, I'll check it. – mr.nothing Jun 13 '13 at 11:56
  • 1
    @mr.nothing, always try your command with ls before using it with rm! – fedorqui Jun 13 '13 at 11:57
  • @fedorqui Probably the best solution. I tried to make something up with find, but I don't think this condition can be made up with it. – glglgl Jun 13 '13 at 11:58
  • 1
    The problem with this solution is, that it won't work recursively. However the question doesn't make it clear if this is wanted or not. – buergi Jun 13 '13 at 12:12
1

The following function could work, I didn't have the time to test it, though.

// $1 = directory to remove
// $2 = exclude pattern
function rmx()
{
    rm -f $(find $1 * | grep -v $2)
}

Call like

rmx get/rid/of/this/ ".*?not-these-files.*?"

Maybe this can at least serve as an idea on one way to approach this problem...

  • find is the right way, but this way is to complicated, it's much easier to exclude the files in the search right away and use find's -delete flag. Check out my anwer for a full example. – buergi Jun 13 '13 at 12:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.