0

I have a directory that has some subdirectories with files in them. I have another directory that has very similar subdirectories but there may be a few that are added or removed. How can I add and remove subdirectories so the two directories have the same structure?

Is there a simple way to do this using a command or tool? Or do I have to do something more complicated like search through every subdirectory and check if it has a matching one?

0

For this answer I used the following tools:

  • Bash
  • comm
  • find
  • xargs

I recommend you to use the GNU version of the last 3 utilities as they can deal with NUL-delimited records.

First, let's declare some variables. It's necessary to use absolute pathnames in all these variables as we'll be changing directories many times:

# The directories that will be compared
original_dir='/path/to/original/directory'
copy_dir='/path/to/copy/directory'

# Text files where we will save the structure of both directories
original_structure="${HOME}/original_structure.txt"
copy_structure="${HOME}/copy_structure.txt"

# Text files where we will separate each subdirectory
# depending on the action we will perform on them
dirs_to_add="${HOME}/dirs_to_add.txt"
dirs_to_remove="${HOME}/dirs_to_remove.txt"

Save the current structure of both directories:

cd -- "${original_dir}"
find . \! -name '.' -type 'd' -print0 | sort -z > "${original_structure}"

cd -- "${copy_dir}"
find . \! -name '.' -type 'd' -print0 | sort -z > "${copy_structure}"

Save the differences between both structures:

comm -23 -z -- "${original_structure}" "${copy_structure}" > "${dirs_to_add}"
comm -13 -z -- "${original_structure}" "${copy_structure}" > "${dirs_to_remove}"

Create the missing directories:

cd -- "${copy_dir}"
xargs -0 mkdir -p -- < "${dirs_to_add}"

Remove the unwanted directories:

cd -- "${copy_dir}"
xargs -0 rm -rf -- < "${dirs_to_remove}"

Remove the text files we created to save the temporal information:

rm -- "${original_structure}" "${copy_structure}"
rm -- "${dirs_to_add}" "${dirs_to_remove}"

Notes

  • This method only copies the structure. It doesn't preserve owners, permissions or attributes. I read that some other tools, like rsync, could preserve them, but I have no experience using them.

  • If you want to put the code above into a script, make sure to implement error handling. For instance, failing to cd into a directory and operating in the incorrect one may lead to catastrophic consequences.

0

Something like this shell function might do:

comparedirs() (
    cd -- "${1?}";
    for d in */; do
        ! [ -d ../"${2?}"/"$d" ] && printf "%s\n" "$d is in '$1' but not in '$2'"
    done
)

A test:

$ mkdir -p left/{a,b,c}
$ mkdir -p right/{a,c,d}
$ comparedirs left right
b/ is in 'left' but not in 'right'
$ comparedirs right left
d/ is in 'right' but not in 'left'

Note, that only looks at subdirectories, not files; and assumes the directories indeed are siblings, i.e. that you can reach one from the other with ../name. (Generalizing to other situation is left as an exercise for the next answer.)

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.