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' _ {}