Seu rm -r *.*~ (o mesmo que rm -r ./*.*~ ) removeria arquivos e diretórios correspondentes a *.*~ que são arquivos e diretórios cujo nome contém um ponto e termina com ~
Mas subdir não contém nenhum ponto, por isso não cabe.
Leia glob (7) e lembre-se de que é a sua concha (não a /bin/rm program!) que faz o globbing .
Então, o que está acontecendo é que você digita rm -r ./*.*~ no seu shell. Seu shell está expandindo isso para rm -r ./test.txt~ ; então ele encontra o programa /bin/rm no seu $PATH , chama fork (2) para criar um processo filho e, em seguida, execve (2) no programa /bin/rm , com uma matriz de argumentos de rm -rf ./test.txt~ so rm nem sequer vê ./subdir
Para que todo arquivo de backup seja removido em qualquer subdiretório direto, digite rm */*.*~ ; com recente bash (versão 4 ou posterior) e zsh você pode remover qualquer arquivo de backup até mesmo no fundo da árvore de arquivos com rm **/*.*
Uma maneira possível de entender o que o shell está fazendo é substituir seu comando (por exemplo, rm ) por echo . Isso deve dar-lhe a expansão (mas leia echo (1) , pois echo está entendendo algumas opções como -n ). Em alguns shells bons, você pode até usar a tecla tab para autocompletar . Estou usando o zsh como meu shell interativo porque gosto de seus recursos de autocompletar.
Por fim, rm (1) sabe sobre -i interativamente antes da remoção). Então eu vou sugerir rm -i **/*~
BTW, se você não sabe sobre sistemas de controle de versão, é hora de aprendê-los (eu recomendo strongmente usar git . ...), especialmente para código "fonte" como arquivos (programas em C ou Python, scripts de shell, etc etc etc ...) e você não precisará de arquivos de backup.