I made a modular bash function for this, based on a compilation of findings:
rmexcept()
{
files=()
for pattern in "$@"
do
files+=(`find . -maxdepth 1 -type f -not -iname "$pattern"`)
done
# uniqfilter -dfor onlyduplicates neededonly ifwhen more than one arg, otherwise rm all files inpattern listprovided
if (($# > 1))
then
printf "%s\n" ${files[@]} | sort | uniq -d | xargs rm
else
printf "%s\n" ${files[@]} | xargs rm
fi
}
It is designed to work with multiple pattern arguments:
rmexcept '*.tex' '*.pdf'
NOTE: The single quotes are necessary! Otherwise bash will expand the wildcard and you will have a number of inputs equal to the matching expansion, which causes every file to eventually repeat, and thus, causes the function to delete everything!
If you don't want to remember this dangerous caveat (I don't), define
rmexcept as follows:
rmexcept()
{
files=()
for pattern in "$@"
do
files+=(`find . -maxdepth 1 -type f -not -iname "*$pattern"`)
done
# uniqfilter -dfor onlyduplicates neededonly ifwhen more than one arg, otherwise rm all files inpattern listprovided
if (($# > 1))
then
printf "%s\n" ${files[@]} | sort | uniq -d | xargs rm
else
printf "%s\n" ${files[@]} | xargs rm
fi
}
And use without wildcards:
rmexcept .tex .pdf
NOTE: You can still make a dangerous mistake by using a prefix *. I'll
keep thinking about how to improve this.
The way I put the find results in an array might not be best practice.
See this thread for more
details.