[SOLVED] Can cp replace newer files with older files recursively?
Linux - GeneralThis Linux forum is for general Linux questions and discussion.
If it is Linux Related and doesn't seem to fit in any other forum then this is the place.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
a@a-NC210-NC110:~/Documents$ ls -l local/
total 0
-rw-rw-r-- 1 a a 0 1 7 21:31 1.txt
-rw-rw-r-- 1 a a 0 1 7 21:31 2.config
-rw-rw-r-- 1 a a 0 1 7 21:31 3.ini
-rw-rw-r-- 1 a a 0 1 7 21:31 abcd
-rw-rw-r-- 1 a a 0 1 7 21:31 efgh.txt
a@a-NC210-NC110:~/Documents$ ls -l remote
total 0
-rw-rw-r-- 1 a a 0 1 7 21:27 1.txt
-rw-rw-r-- 1 a a 0 1 7 21:27 2.config
-rw-rw-r-- 1 a a 0 1 7 21:27 3.ini
-rw-rw-r-- 1 a a 0 1 7 21:27 abcd
-rw-rw-r-- 1 a a 0 1 7 21:27 efgh.txt
Nota Bene: 1) The directory local's contents are newer than remote. 2) local's DoNotDelete.me is left unchanged.
Now I attempt to copy over the older choice contents from the directory remote into the target directory local replacing newer files. (old replace new)
ATTEMPT 01:
remote/
Code:
a@a-NC210-NC110:~/Documents$ cp -ap remote/ local
a@a-NC210-NC110:~/Documents$ ls -l local/total 0
-rw-rw-r-- 1 a a 0 1 7 21:31 1.txt
-rw-rw-r-- 1 a a 0 1 7 21:31 2.config
-rw-rw-r-- 1 a a 0 1 7 21:31 3.ini
-rw-rw-r-- 1 a a 0 1 7 21:31 abcd
-rw-rw-r-- 1 a a 0 1 7 21:42 DoNotDelete.me
-rw-rw-r-- 1 a a 0 1 7 21:31 efgh.txt
As you see, the files in local still have their original modification times: "21:31". Thus the newer files weren't replaced by the older files, confirming this attempt's failure. However one success is that the file that only exists in local (DoNotDelete.me) was not deleted nor changed.
ATTEMPT 02:
remote/*
Code:
a@a-NC210-NC110:~/Documents$ cp -ap remote/* local
a@a-NC210-NC110:~/Documents$ ls -l local
total 4
-rw-rw-r-- 1 a a 0 1 7 21:27 1.txt
-rw-rw-r-- 1 a a 0 1 7 21:27 2.config
-rw-rw-r-- 1 a a 0 1 7 21:27 3.ini
-rw-rw-r-- 1 a a 0 1 7 21:27 abcd
-rw-rw-r-- 1 a a 0 1 7 21:42 DoNotDelete.me
-rw-rw-r-- 1 a a 0 1 7 21:27 efgh.txt
drwxrwxr-x 2 a a 4096 1 7 21:27 remote
Attempt 02 succeeded in: 1) Copying over newer files with older files; 2) Files solely existing in local remain unchanged.
Unfortunately the /* on the end of "remote/*" probably means we can't execute this recursively. Let's find out.
ATTEMPT 03:
Same as Attempt02 but with recursion.
For Attempt 03, first let me make the complex directory structure below, with identical modification times as above:
Code:
a@a-NC210-NC110:~/Documents$ ls -l local/b/3/ii/local/ local/b/3/ii/mozilla/
local/b/3/ii/local/:
total 4
-rw-rw-r-- 1 a a 0 1 7 21:31 1.txt
-rw-rw-r-- 1 a a 0 1 7 21:31 2.config
-rw-rw-r-- 1 a a 0 1 7 21:31 3.ini
-rw-rw-r-- 1 a a 0 1 7 21:31 abcd
-rw-rw-r-- 1 a a 0 1 7 21:42 DoNotDelete.me
-rw-rw-r-- 1 a a 0 1 7 21:31 efgh.txt
drwxrwxr-x 2 a a 4096 1 8 10:41 New
local/b/3/ii/mozilla/:
total 0
-rw-rw-r-- 1 a a 0 1 7 21:31 1.txt
-rw-rw-r-- 1 a a 0 1 7 21:31 2.config
-rw-rw-r-- 1 a a 0 1 7 21:31 3.ini
-rw-rw-r-- 1 a a 0 1 7 21:31 abcd
-rw-rw-r-- 1 a a 0 1 7 21:31 efgh.txt
a@a-NC210-NC110:~/Documents$ ls -l remote/b/3/ii/local/ remote/b/3/ii/mozilla/
remote/b/3/ii/local/:
total 4
-rw-rw-r-- 1 a a 0 1 7 21:27 1.txt
-rw-rw-r-- 1 a a 0 1 7 21:27 2.config
-rw-rw-r-- 1 a a 0 1 7 21:27 3.ini
-rw-rw-r-- 1 a a 0 1 7 21:27 abcd
-rw-rw-r-- 1 a a 0 1 7 21:27 efgh.txt
drwxrwxr-x 2 a a 4096 1 7 21:27 New
remote/b/3/ii/mozilla/:
total 0
-rw-rw-r-- 1 a a 0 1 7 21:27 1.txt
-rw-rw-r-- 1 a a 0 1 7 21:27 2.config
-rw-rw-r-- 1 a a 0 1 7 21:27 3.ini
-rw-rw-r-- 1 a a 0 1 7 21:27 abcd
-rw-rw-r-- 1 a a 0 1 7 21:27 efgh.txt
Now I will try the method in Attempt02 to see if it works recursively:
Code:
a@a-NC210-NC110:~/Documents$ cp -ap remote/* local
a@a-NC210-NC110:~/Documents$ ls -l local/b/3/ii/local/ local/b/3/ii/mozilla/
local/b/3/ii/local/:
total 4
-rw-rw-r-- 1 a a 0 1 7 21:27 1.txt
-rw-rw-r-- 1 a a 0 1 7 21:27 2.config
-rw-rw-r-- 1 a a 0 1 7 21:27 3.ini
-rw-rw-r-- 1 a a 0 1 7 21:27 abcd
-rw-rw-r-- 1 a a 0 1 7 21:42 DoNotDelete.me
-rw-rw-r-- 1 a a 0 1 7 21:27 efgh.txt
drwxrwxr-x 2 a a 4096 1 7 21:27 New
local/b/3/ii/mozilla/:
total 0
-rw-rw-r-- 1 a a 0 1 7 21:27 1.txt
-rw-rw-r-- 1 a a 0 1 7 21:27 2.config
-rw-rw-r-- 1 a a 0 1 7 21:27 3.ini
-rw-rw-r-- 1 a a 0 1 7 21:27 abcd
-rw-rw-r-- 1 a a 0 1 7 21:27 efgh.txt
Contrary to my expectation, IT WORKS!!! The "/*" at the end of the source directory ("remote/*") is integral to replacing newer files with older ones. Again, files solely existing in target directory remain unchanged. Hence the cp command can replace newer files with older files recursively, when logged in as a regular user and copying non-hidden folders.
Everyone probably wants to know why would anyone want to replace newer files with older files? Those who want to to restore previously saved configuration files onto a freshly installed OS. Since the OS (local) drive has just been installed, most mod times will be the time the system was installed. Thus you can't use rsync -au since the option "u" will only replace older files with newer files, and you can't use rsync -a because rsync will see that the file already exists and thus skip it(saving BIG time).
ATTEMPT 04:
hidden files, logged in as root
Now let me apply this to updating the config files in my /home/a directory when logged in as root:
Code:
root@a-NC210-NC110:/home/a$ sudo su
root@a-NC210-NC110:/home/a# cp -ap /media/LG/AC/bckup/Install/3_UbuntuLXDE14.04/home/a/* /home/a
root@a-NC210-NC110:/home/a# ls -l /media/LG/AC/bckup/Install/3_UbuntuLXDE14.04/home/a/.codeblocks
total 308
-rw-rw-r-- 1 a adm 29766 1 6 22:50 cbKeyBinder10.ini
-rw-rw-r-- 1 a adm 29766 1 6 22:50 cbKeyBinder10.ini.bak
-rw-rw-r-- 1 a adm 119276 1 6 22:50 default.conf
-rw-rw-r-- 1 a adm 29568 1 6 22:50 night.cbKeyBinder10.ini
-rw-rw-r-- 1 a adm 29568 1 6 22:50 night.cbKeyBinder10.ini.bak
-rw-rw-r-- 1 a adm 59067 1 6 22:50 night.conf
root@a-NC210-NC110:/home/a# ls -l /home/a/.codeblocks
total 312
-rw-rw-r-- 1 a adm 29766 1 6 22:50 cbKeyBinder10.ini
-rw-rw-r-- 1 a adm 29766 1 6 22:50 cbKeyBinder10.ini.bak
-rw-rw-r-- 1 a adm 119276 1 6 22:50 default.conf.bak
-rw-rw-r-- 1 a adm 29568 1 6 22:50 night.cbKeyBinder10.ini
-rw-rw-r-- 1 a adm 29568 1 6 22:50 night.cbKeyBinder10.ini.bak
-rw-rw-r-- 1 a adm 59067 1 6 22:50 night.conf
drwxr-xr-x 3 a a 4096 1 7 11:10 share
You can clearly see, default.conf exists in the source directory but not in the target directory!
All of a sudden, the "source/*" method does not work! Why? Does it have to do with running it from root? Is it because of the config files mostly are located in folders that start with "."? The program I am working on must be run from root, so there is no choice. What can I do?
Last edited by andrew.comly; 01-08-2016 at 10:07 PM.
Reason: SPACING
For some reason I was confusing cp with something else, and thinking -R and -r were different. Sorry for not checking that before posting. I don't actually use cp very often, preferring rsync most of the time unless it's just a file or two.
Wouldn't it be easier to remove the newer files first, and then not worry about overwrites, or is that a problem? I'm not sure I completely understand your situation.
a@a-NC210-NC110:~/Documents$ cp -ap remote/ local
a@a-NC210-NC110:~/Documents$ ls -l local/total 0
-rw-rw-r-- 1 a a 0 1 7 21:31 1.txt
-rw-rw-r-- 1 a a 0 1 7 21:31 2.config
-rw-rw-r-- 1 a a 0 1 7 21:31 3.ini
-rw-rw-r-- 1 a a 0 1 7 21:31 abcd
-rw-rw-r-- 1 a a 0 1 7 21:42 DoNotDelete.me
-rw-rw-r-- 1 a a 0 1 7 21:31 efgh.txt
There is something very strange about your version of cp, because when I run that same command "local" ends up with a subdirectory "remote" with all the files from that source directory.
Code:
$ mkdir remote; touch remote/file{1,2}
$ mkdir local; touch local/file{1,2,3}
$ cp -ap remote/ local
$ ls -l remote
total 0
-rw-rw-r--. 1 rnichols rnichols 0 Jan 9 11:56 file1
-rw-rw-r--. 1 rnichols rnichols 0 Jan 9 11:56 file2
$ ls -lR local
local:
total 4
-rw-rw-r--. 1 rnichols rnichols 0 Jan 9 11:57 file1
-rw-rw-r--. 1 rnichols rnichols 0 Jan 9 11:57 file2
-rw-rw-r--. 1 rnichols rnichols 0 Jan 9 11:57 file3
drwxrwxr-x. 2 rnichols rnichols 4096 Jan 9 11:56 remote
local/remote:
total 0
-rw-rw-r--. 1 rnichols rnichols 0 Jan 9 11:56 file1
-rw-rw-r--. 1 rnichols rnichols 0 Jan 9 11:56 file2
The trailing "/" on that source directory is of no significance to cp.
And on the Operating System's drive I not only have the 2352 newer config files/folders I want to replace but also 8177 (10529 - 2352) other vital config files/folders I don't want to touch.
Wouldn't it be easier to remove the newer files first
you didn't mean manually delete them one by one did you? Being that you probably meant remove en masse, what method specifically would you use to "remove" those 2352 files/folders mixed among 8177 other vital config files/folders that you mustn't touch?
There is something very strange about your version of cp
You're right, it looks like I cut and pasted incorrectly.
My Attempt 01 redone:
Code:
a@a-NC210-NC110:~/Documents$ ls -l local remote
local:
total 4
-rw-rw-r-- 1 a a 0 1 7 21:42 DoNotDelete.me
drwxrwxr-x 2 a a 4096 1 7 21:31 New
remote:
total 4
-rw-rw-r-- 1 a a 0 1 7 21:27 1.txt
-rw-rw-r-- 1 a a 0 1 7 21:27 2.config
-rw-rw-r-- 1 a a 0 1 7 21:27 3.ini
-rw-rw-r-- 1 a a 0 1 7 21:27 abcd
drwxrwxr-x 7 a a 4096 1 7 20:34 b
-rw-rw-r-- 1 a a 0 1 7 21:27 efgh.txt
a@a-NC210-NC110:~/Documents$ cp -ap remote/ local
a@a-NC210-NC110:~/Documents$ ls -l local
total 8
-rw-rw-r-- 1 a a 0 1 7 21:42 DoNotDelete.me
drwxrwxr-x 2 a a 4096 1 7 21:31 New
drwxrwxr-x 3 a a 4096 1 11 10:25 remote
Quote:
Originally Posted by rknichols
The trailing "/" on that source directory is of no significance to cp.
You're right. Certainly by the above re-do of attempt 01 the trailing "/" has absolutely no significance at all.
I guess my cli skills just aren't there yet.
Last edited by andrew.comly; 01-10-2016 at 09:07 PM.
Reason: credit
Why cp? You should be using rsync which provides a wide array of options (including copy only if newer). cp is good for basic copy operations but it's not good at operations where copying under specific conditions is required. It's basically going to always copy.
rsync is better at what you desire. For example, rsync -ruptv /src/ /dst/
See the rsync man page for explanation of options.
isn't that a case for a dedicated application, like e.g. unison (or rsync)?
Use rsync and unison to replace newer files/folders with older files/folders?
I always have used rsync to do the opposite: replace older files with newer files.
How can rsync/unison be used to replace newer files with older ones?
Nota Bene:
Quote:
Originally Posted by andrew.comly
Everyone probably wants to know why would anyone want to replace newer files with older files? Those who want to to restore previously saved configuration files onto a freshly installed OS. Since the OS (local) drive has just been installed, most mod times will be the time the system was installed. Thus you can't use rsync -au since the option "u" will only replace older files with newer files, and you can't use rsync -a because rsync will see that the file already exists and thus skip it
Maybe the sentence above "Since the OS (local) drive has just been installed, most mod times will be the time the system was installed." is written unclearly. Perhaps it would have been clearer if I had written
Since the OS (local) drive has just been installed, most mod times will be the time the system was installed(just now), thus newer than the config files you have saved on the remote file.
Why cp? You should be using rsync which provides a wide array of options (including copy only if newer)
...
rsync is better at what you desire. For example, rsync -ruptv /src/ /dst/
By the options above (-u) you will replace older with newer, not the desired action of replacing newer with older.
Replacing newer files with older ones is the opposite of your clause above "(including copy only if newer)".
In my situation, I am trying to copy over configurations from a previous installation to a system THAT WAS JUST INSTALLED. Since the OS (local) drive has just been installed, most mod times will be the time the system was installed. That is, the local OS's /home/a config files(No Configuration) will be newer than the remote hard drive's /home/a's config files (Desired Configuration).
Since the desired config files are OLDER than the newer config files, therefore you can't use rsync -au since the option "u" will only replace older files with newer files, and you can't use rsync -a because rsync will see that the file already exists and thus skip it.
I always have used rsync to do the opposite: replace older files with newer files.
May I ask, are you sure that rsync be used to replace newer files with older ones?
Last edited by andrew.comly; 01-10-2016 at 10:11 PM.
Reason: examples
You're right. Certainly by the above re-do of attempt 01 the trailing "/" has absolutely no significance at all.
That's true for cp and many other commands, but that trailing "/" on a source directory is very significant for rsync, where it does mean to take the contents of a directory and not the directory itself, which is what you were trying to do with cp. And for cp and many other commands, a trailing "/" on a destination means "an existing directory with that name." Sometimes it's significant, sometimes not.
Code:
$ ls /tmp/xxx
ls: cannot access /tmp/xxx: No such file or directory
$ cp -a /etc/profile /tmp/xxx/
cp: cannot create regular file `/tmp/xxx/': Is a directory
$ mkdir /tmp/xxx
$ cp -a /etc/profile /tmp/xxx/
$ ls -l /tmp/xxx
total 4
-rw-r--r--. 1 rnichols rnichols 1796 Oct 2 2013 profile
So, cp would have replaced the newer files just fine were it not for the fact that your command line caused it to place those files in a new subdirectory rather than replacing existing files. Using rsync as others have suggested, does allow you to name a directory and copy its contents rather than the directory itself.
And yes, rsync is quite willing to replace a newer file with an older one. In fact, you have to go out of your way to tell it not to do that ("-u" or "--update" option for "skip files that are newer on the receiver").
Last edited by rknichols; 01-10-2016 at 09:53 PM.
Reason: Add example of cp destination with trailing "/"
Now I will try the method in Attempt02 to see if it works recursively:
a@a-NC210-NC110:~/Documents$ cp -ap remote/* local
...
Contrary to my expectation, IT WORKS!!! The "/*" at the end of the source directory ("remote/*") is integral to replacing newer files with older ones.
I feel by the content of each of the responses above, that some of you may have overlooked the fact that I can already do this successfully from user "a" with non-hidden folders, but not from user "root" with hidden folders.
I feel by the content of each of the responses above, that some of you may have overlooked the fact that I can already do this successfully from user "a" with non-hidden folders, but not from user "root" with hidden folders.
That is simply because "/*" does not, by default, match names that start with ".". You can either continue to fight with that, or switch to rsync, which gives you a cleaner way to ask that all contents of a directory be copied.
Code:
cp -a remote/.[^.]* remote/* destination
# or
shopt -s dotglob
cp -a remote/* destination
shopt -u dotglob
# vs
rsync -a remote/ destination
And yes, rsync is quite willing to replace a newer file with an older one. In fact, you have to go out of your way to tell it not to do that ("-u" or "--update" option for "skip files that are newer on the receiver").
:O It never occured to me that rsync could replace a newer file with an older one.
As usual, when learning commands it is significantly difficult to understand every little nuance for each manual page from the start. Thanks for exposing my preconceived notion and I'll keep improving my ability to read the manual pages closer and closer.
I'll go do some experiments and then post my results.
Last edited by andrew.comly; 01-11-2016 at 06:11 AM.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.