How to merge one directory into another using Bash?

I am looking for a shell script that merges files from one directory to another.

Example:

html/ a/ b.html index.html html_new/ a/ b2.html b.html 

Using:

 ./mergedirs.sh html html_new 

Result:

 html/ a/ b.html b2.html index.html 

html/a/b.html been replaced by html_new/a/b.html
html/a/b2.html was copied from html_new/a/b2.html
html/index.html remained untouched

+68
command-line scripting bash shell sh
Dec 31 '10 at 20:42
source share
7 answers

You probably just want cp -R $1/* $2/ - a recursive copy.

(If there may be hidden files (those whose names begin with a dot), you must prefix this command with shopt -s dotglob; to make sure they match.)

+78
Dec 31 '10 at 20:46
source share
 cp -RT source/ destination/ 

All files and directories in source will be in destination . For example, source/file1 will be copied to destination/file1 .

The -T flag stops copying source/file1 to destination/source/file1 . (Unfortunately, cp on macOS does not support the -T flag.)

+78
Nov 22 '13 at 10:22
source share

Look att rsync

 rsync --recursive html/ html_new/ 

Rsync got a lot of flags to install, so see the rsync man page for details

+16
Dec 31 '10 at 21:05
source share

Just use rsync - it's a great tool for copying and merging files locally in addition to remote copying.

 rsync -av /path/to/source_folder/ /path/to/destination_folder/ 

Note that the slash in the source folder is necessary to copy only the contents of source_folder to the destination. If you do not enable it, it will copy the source folder and its contents, which is probably not what you are looking for, because you want to merge the folders.

+6
Dec 23 '13 at 17:35
source share

Does cp -r not work?

 cp -r html_new/* html 

or (since the first version will not copy .something files)

 cd html_new; cp -r . ../html 

Note that -r reads from pipes if any of the files in the copied directory are pipes. To avoid this, use -r instead.

+2
Dec 31 '10 at 20:45
source share
 cd html cp -r . /path/to/html_new 
+2
Dec 31 '10 at 20:45
source share

Despite the fact that this question and its accepted answer are ancient, I add my answer, because existing ones using cp either do not handle some edge cases or require interactive work. Often, cross-cases / scripting ability / portability / multiple sources do not matter, but simplicity wins in this case, and it is better to use cp directly with fewer flags (as in other answers) to reduce cognitive load, but for those other times (or for a reliable reuse function) this call function is useful and, by the way, is not bash-specific (I understand that this question was about bash, though, so it's just a bonus in this case). Some flags may be shortened (for example, using -a ), but I have explicitly included everything in a long form (with the exception of -R , see below) for an explanation. Obviously, just remove any flags if there is some feature that you don’t want (or you are on an OS other than posix, or your cp version does not handle this flag - I tested this on GNU coreutils 8.25 cp ):

 mergedirs() { _retval=0 _dest="$1" shift yes | \ for _src do cp -R --no-dereference --preserve=all --force --one-file-system \ --no-target-directory "${_src}/" "$_dest" || { _retval=1; break; } done 2>/dev/null return $_retval } mergedirs destination source-1 [source-2 source-3 ...] 

Explanation:

  • -R : has slightly different semantics from -R / --recursive on some systems (especially regarding special files in source directories), as explained in this answer
  • --no-dereference : never follow symbolic links in SOURCE
  • --preserve=all : save the specified attributes (default: mode, property, timestamps), if additional attributes are possible: context, links, xattr, all
  • --force : if the existing destination file does not open, delete it and try again
  • --one-file-system : stay in this file system
  • --no-target-directory : treat DEST as a regular file (explained in this answer , namely: If you do a recursive copy and the source is a directory, then cp -T copies the content of the source into the destination, rather than copying the source itself. )
  • [with input channel from yes ]: even with --force , in this particular recursive mode, cp still asks for each file to be scrambled, so we achieve a non-interactive output from it yes li>
  • [output to channel /dev/null ]: does this disable a messy question line on cp: overwrite 'xx'? lines cp: overwrite 'xx'?
  • [return-val and early exit]: this ensures that the loop ends as soon as a failure occurs, and returns 1 if an error occurs

BTW:

  • The Flemish new flag, which I also use with this in my system, is --reflink=auto to create so-called β€œlight copies” (copy to write with the same speed advantages as hard linking, and the same size benefits to and in inverse proportion to how far the files will diverge in the future). This flag was adopted in recent GNU cp and does more than no-op with compatible file systems on the latest Linux kernels. YMWV-a-lot on other systems.
+2
May 27 '16 at 19:25
source share



All Articles