3
\$\begingroup\$

imaging a folder structure like:

Peter
|- Cats
   |- Mini
   |- Maunz 
   |- Tippsi
|– Dogs
   |- Brutus

Eva
|- animals
   |- Mini
   |- Brutus

I'd like to delete all subfolders in Peter/*/ if they not present in Eva/animals/ (Maunz and Tippsi). This is what I have so far. It's working but it feels as my combination of loop and find is not the best solution:

for dir in ./Peter/*/*/
do
   dir=${dir%*/}
   if find './Eva/animals' -type d -name ${dir##*/} -exec false {} +
   then
      echo "${dir%*/} not found and deleted"
      rm -rf ${dir%*/}
    fi
done

For learning, can this code be optimized?

\$\endgroup\$
3
\$\begingroup\$

find is good for finding files and directories recursively in a filesystem tree. Based on your description and example, you probably don't need that. If you want to check that some directory foo exists directly under /some/path, it's much simpler and more efficient to use the test or [ builtin.

There are some other minor issues in the posted code:

  • It's a good practice (and often necessary) to double-quote variables in command parameters. For example instead of rm -rf ${dir%*/} write rm -rf "${dir%*/}"

  • Instead of writing ${dir%*/} 3 times, it would be better to store in a variable. In fact you did store the result of the first "call" in a variable, and since subsequent calls on the modified value will be the same, you could have used $dir.

  • I think dir=${dir%/} is equivalent to dir=${dir%*/} but simpler.

Putting the above together, a cleaner, more efficient alternative:

#!/usr/bin/env bash

for dir in ./Peter/*/*/
do
    dir=${dir%/}
    name=${dir##*/}
    if ! [ -d "./Eva/animals/$name" ]
    then
        echo "$dir not found and deleted"
        rm -rf "$dir"
    fi
done
\$\endgroup\$

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.