Если у вас есть bash 4+ (проверьте с помощью bash --version), вы можете сделать это в две строки:
shopt -s globstar
for f in ./**/; do [[ -f "$f"/DONOTDELETE.TXT ]] || rm -f "$f"/*; done
Обратите внимание, что shopt -s globstar должен находиться на отдельной строке - не просто добавлять его к циклу for с помощью ; ,
./**/ расширяется до каждого подкаталога в текущем каталоге, и их подкаталоги рекурсивно. Если вы хотите пройти вниз по дереву только на один уровень, используйте вместо этого ./*/ (и не беспокойтесь о настройке globstar); если вам нужен более точный контроль, вам придется возиться с find (в частности, с -maxdepth и -mindepth ). Я использую ./**/ вместо **/ в случае, если любой из ваших каталогов начинается с -: это мешает их видеть как
[[ -f "$f"/DONOTDELETE.TXT ]] проверяет, существует ли этот файл и является ли он файлом (если вы хотите, чтобы он работал, даже если DONOTDELETE.TXT может отличаться от файла, используйте -e вместо -f). Строго говоря, вам не нужен / in, так как $ f содержит косую черту, но я думаю, что в этом случае она выглядит лучше, и в целом избыточные косые черты безвредны. || означает ИЛИ - если (и только если) этот тест оценивается как ложный, то будет выполнен код справа от него, в этом случае rm -f "$f"/* - который удаляет все файлы, кроме скрытых.
Если вы также хотите удалить скрытые файлы, вы можете использовать что-то вроде:
for f in ./**/; do [[ -f "$f"/DONOTDELETE.TXT ]] || rm -f "$f"/* "$f"/.*; done