If you have bash 4+ (check with bash --version
), you can do this in a two-liner:
shopt -s globstar
for f in ./**/; do [[ -f "$f"/DONOTDELETE.TXT ]] || rm -f "$f"/*; done
Note that shopt -s globstar
needs to be on its own line - don't just prepend it to the for loop with a ;
.
./**/
expands to every subdirectory in the current directory, and their subdirectories recursively. If you only want to go down the tree a single level, use ./*/
instead (and don't bother setting globstar); if you want finer control than that, you'll have to mess around with find
instead (specifically the -maxdepth
and -mindepth
options). I use ./**/
instead of **/
in case any of your directories begin with a -
: this stops them from being seen as
[[ -f "$f"/DONOTDELETE.TXT ]]
tests to see if that file exists and is a file (if you want it to work even if DONOTDELETE.TXT may be something other than a file, use -e
instead of -f
). Strictly speaking, you don't need the /
in there, since $f contains a trailing slash, but I think it looks better this way, and in general redundant forward-slashes are harmless. ||
means OR - if (and only if) that test evaluates to false, then the code to the right of it will be executed, in this case rm -f "$f"/*
- which deletes every file, except the hidden ones.
If you want to delete hidden files too, you can use something like:
for f in ./**/; do [[ -f "$f"/DONOTDELETE.TXT ]] || rm -f "$f"/* "$f"/.*; done
-exec list {}/*
instead of-printf '%h'
. If it shows the correct files only, maybe you can try-exec rm -f {}/*
(Caution: This is dangerous!). Also, this maybe useful.( find /testftp -type d ; find /testftp -type f -iname DONOTDELETE.TXT -exec list {} \; ) | sort | uniq -u
Output is : ` find: list: No such file or directory /testftp /testftp/logger /testftp/logs ` DONOTDELETE.TXT is under ` /testftp/logger `ls
notlist
(always forget it!)