How to move and overwrite subdirectories (and files) to parent directory?

I have a ton of files and dirs in a subdirectory I want to move to the parent directory. There are already some files and dirs in the target directory which need to be overwritten. Files that are only present in the target should be left untouched. Can I force mvto do that? It (mv * ..) complains

mv: cannot move `xyz' to `../xyz': Directory not empty

What am I missing?

Asked By: EricSchaefer

||

You will have to copy them to the destination and then delete the source, using the commands cp -r * .. followed by rm -rf *.

I don’t think you can “merge” directories using mv.

Answered By: dogbane

Here’s a script that moves files from under /path/to/source/root to the corresponding path under /path/to/destination/root.

  • If a directory exists in both the source and the destination, the contents are moved-and-merged recursively.
  • If a file or directory exists in the source but not in the destination, it is moved.
  • Any file or directory that already exists in the destination is left behind. (In particular merged directories are left behind in the source. This is not easy to fix.)

Beware, untested code.

export dest='/path/to/destination/root'
cd /path/to/source/root
find . -type d ( -exec sh -c '[ -d "$dest/$0" ]' {} ; -o 
                  -exec sh -c 'mv "$0" "$dest/$0"' {} ; -prune ) 
    -o -exec sh -c '
        if ! [ -e "$dest/$0" ]; then
          mv -f "$0" "$dest/$0";
        fi
' {} ;

rsync would probably be a better option here. It’s as simple as rsync -a subdir/ ./.

My test tree in filename:contents format:

./file1:root
./file2:root
./dir/file3:dir
./dir/file4:dir
./subdir/dir/file3:subdir
./subdir/file1:subdir

Running rsync:

$ rsync -a -v subdir/ ./
sending incremental file list
./
file1
dir/
dir/file3

Gives:

./file1:subdir
./file2:root
./dir/file3:subdir
./dir/file4:dir
./subdir/dir/file3:subdir
./subdir/file1:subdir

And then, to emulate mv, you probably want to remove the source directory:

$ rm -r subdir/

Giving:

./file1:subdir
./file2:root
./dir/file3:subdir
./dir/file4:dir

If this is wrong, can you please provide a similar example (e.g. using my test tree from near the top of this answer) with the desired result?

Answered By: Mikel

rsync can delete the source after copying with the --remove-source-files parameter.

From the rsync man page:

--remove-source-files   sender removes synchronized files (non-dir)
Answered By: Mike Chen

You can do this with cp and rm, but without copying the massive amount of data you are (presumably) trying to avoid transferring. @mattdm alluded to this in his comment, and an answer for another question has a more complete discussion about various options.

cp -rlf source destination
rm -r source

Essentially, the -l option for the cp command creates hard links to files rather than copying their data to new files.

Answered By: palswim

If you have enough storage you can do it the following way:

mv -bfv directory_1/* directory_2/ # all duplicate source files/directories 
                                   # will have ~ appended to them
find -name "*~" -delete            # will recursively find and delete all files 
                                   # with ~ on the end

Make sure there aren’t any important files with a ~ on the end of them, but if there are you can add --suffix=whateveryouwant instead of the default.

Answered By: 4D3H2

This thread is out there for years and still ranks #1 on google so i wanted to add another method.
How i usually do this:
packing the subdir content into a tarball, moving the tarball up to the parent directory and then extract it with the default –overwrite behaviour. This does exactly what you’re looking for. Afterwards you can remove your subdir.

cd xyz
tar -cvzpf tmp.tar.gz *
mv tmp.tar.gz ../tmp.tar.gz
cd ..
tar -xvzpf tmp.tar.gz
rm -rf xyz
rm -f tmp.tar.gz
Answered By: Simon Kraus
Categories: Answers Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.