3

I have two dirs dir1 and dir2 that have hundreds of subdirectories at depth 1. I only need information of the subdirectory names that are common between dir1 and dir2 and systematically delete them from dir2. I don't need to compare files or content of files. Performing

diff -qr dir_one dir_two | sort

produces the filenames as well, which I'm not interested at the moment.

  • Performing the above command without recursion enable the identification of only unique directories. But I'm still not sure how to identify the common directories and delete them from dir2 – WanderingMind Oct 25 '16 at 14:46
2

For your use case you can avoid to identify the common directories because rm -rf just ignores non-existing ones.

So it's enough to find all directories in dir1 and delete them from dir2:

find dir1 -mindepth 1 -maxdepth 1 -type d -printf "dir2/%f\0" |xargs -0 rm -rf --

Some explanations. By default find would print all the dirs with full path which is dir1. So we are using -printf to print only the file name without leading directories (%f) plus the other path "dir2" where we want to delete. Furthermore we terminate the string with null byte '\0' rather than newline to use xarg option -0 which makes all this safe regarding filenames with spaces. Then xargs will read stdin and execute the rm command by adding all strings as arguments.

Note before actually deleting them you may test your command line by adding echo to only print the rm commands:

find dir1 -mindepth 1 -maxdepth 1 -type d -printf "dir2/%f\0" |xargs -0 echo rm -rf --

To only list the common directories you could use ls instead of rm (adding 2>/dev/null to ignore non-existing ones):

find dir1 -mindepth 1 -maxdepth 1 -type d -printf "dir2/%f\0" |xargs -0 -r ls -d -- 2>/dev/null
  • This seems to work. Thank you. A little more explanation on how the printf and xargs part of the command works, I can accept your answer. – WanderingMind Oct 25 '16 at 15:43
  • Can you help me to extend this (i) to do it recursively at multiple depths (ii) delete the subdirectories that are NOT common. – WanderingMind Nov 5 '16 at 17:38
1
comm -1 -3 <( cd dir1 && find -maxdepth 1 -type d | sort ) <( cd dir2 && find -maxdepth 1 -type d | sort ) | ( cd dir2 && xargs rm -rf )

with line breaks for readability:

comm -1 -3 <( cd dir1 && find -maxdepth 1 -type d | sort ) \
           <( cd dir2 && find -maxdepth 1 -type d | sort ) \
                | ( cd dir2 && xargs rm -rf )

explanation

find -maxdepth 1 -type d

list only directories without subdirectories.

cd dir1 && find -maxdepth 1 -type d | sort

first change to directory then list directories.

<( ... )

process substitution.

comm -1 -3 <( ... ) <( ... )

take first input and second input and print lines unique to second input. in effect this will print directories which are in dir2 but not in dir1.

... | ( cd dir2 && xargs rm -rf )

change working directory to dir2 then execute rm -rf with output of previous command as arguments. in effect this will delete the directories which are in dir2 but not in dir1.

test first by removing the pipe to xargs and inspecting the output.

-1
find dir1 dir2 -maxdepth 2 | egrep '/' | xargs --max-args 1 basename | sort | uniq -c  | egrep -v '^      1 ' | while read n de ; do echo rm -rfv dir2/$de ; done

remove the echo when correct.

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.