Home > Software design >  Merge (via moving) two directories and subdirectories, replacing exisiting files (not folders!)
Merge (via moving) two directories and subdirectories, replacing exisiting files (not folders!)

Time:01-08

I have two directories, with the following structure:

root_a
- dir_b
-- file
-- file
-- ...
- dir_c
-- file
-- file
-- ...

root_b
- dir_b
-- file
-- file
-- ...
- dir_c
-- file
-- file
-- ...

Each subdirectory (i.e., dir_b and dir_c) contain 10s of thousands of files.

I want to merge root_a and _root_b into a target directory, root_c. I.e. I want root_c/dir_b to contain files from both root_a/dir_b and root_b/dir_b, and root_c/dir_c to contain files from both root_a/dir_c and root_b/dir_c.

E.g

root_c
- dir_b
-- file (e.g. from root_a/dir_b)
-- file (e.g. from root_b/dir_c)
-- ...
- dir_c
-- file (e.g. from root_a/dir_b)
-- file (e.g. from root_b/dir_c)
-- ...

How can I do this?

I tried using bash mv, but this does not work because I have too many files:

#!/bin/bash

# check if the number of arguments is correct
if [ $# -ne 2 ]; then
  echo "Usage: $0 SOURCE TARGET"
  exit 1
fi

# set variables for the source and target directories
src=$1
tgt=$2

# move all directories and files from the source to the target, replacing any existing files
mv -f $src/* $tgt

Note: I do not want to COPY. I want to MOVE files. I have limited space, and cannot copy and then delete the originals. Plus, that would take a very long time...

CodePudding user response:

If you have mv from GNU coreutils:

#!/bin/bash

for subdir in dir_b dir_c; do
    find {root_a,root_b}/"$subdir" -type f -exec mv -t root_c/"$subdir" {}  
done

CodePudding user response:

Something like this maybe:

#!/usr/bin/env bash

shopt -s nullglob globstar dotglob
dir_b_files_a=(root_a/dir_b/**/*)
dir_b_files_b=(root_b/dir_b/**/*)
dir_c_files_a=(root_a/dir_c/**/*)
dir_c_files_b=(root_b/dir_c/**/*)
shopt -u nullglob globstar dotglob

mkdir -vp root_c/dir_{b,c} || exit

printf 'Moving files from %s to %s\n' 'root_a/dir_b' 'root_c/dir_b'
for f in "${dir_c_files_a[@]}"; do
  echo mv -v -- "$f" root_c/dir_b || exit
done

printf 'Moving files from %s to %s\n' 'root_b/dir_b' 'root_c/dir_b'
for f in "${dir_c_files_b[@]}"; do
  echo mv -v -- "$f" root_c/dir_b || exit
done

printf 'Moving files from %s to %s\n' 'root_a/dir_c' 'root_c/dir_c'
for f in "${dir_c_files_a[@]}"; do
  echo mv -v -- "$f" root_c/dir_c || exit
done

printf 'Moving files from %s to %s\n' 'root_b/dir_c' 'root_c/dir_c'
for f in "${dir_c_files_b[@]}"; do
  echo mv -v -- "$f" root_c/dir_c || exit
done

  • The command line option/args was not included, all the paths are hard coded though.

  • Remove the echo if you're ok with the result/output.


with find something like.

mkdir -vp root_c/dir_{b,c} || exit

printf 'Moving files from %s %s to %s\n' root_{a,b}/dir_b 'root_c/dir_b'
find root_{a,b}/dir_b -type f -exec sh -c 'mv -- "$@" root_c/dir_b' _ {}  

printf 'Moving files from %s %s to %s\n' root_{a,b}/dir_c 'root_c/dir_c'
find root_{a,b}/dir_c -type f -exec sh -c 'mv -- "$@" root_c/dir_c' _ {}  
  •  Tags:  
  • bash
  • Related