0

This is a specific question about using cp within find while preserving directory structure. This is the way that seems like it should work, but perhaps there is a way to do it better. The reason I am using find is because I only want to copy files of a certain age.

I have a directory structure like this. The operating system is Ubuntu 16.04.

folders
   folder1
     file1.txt
   folder2
     file1.txt
     file2.txt
   folder3
     file1.txt

I am using the cp command within the find command, as so...

find "$pathtofolder"/* -mmin +"$timeinmins" -type f -name "*.txt" -exec cp --parents {} /var/www/website/archives \;

The --parents flag copies the entire path to the files so I get something like archives/var/www/website/folders/folder1/file1.txt. This is not what I'm going for. I just want archives/folder1/file1.txt.

The -R and -a flags do not work in this statement within find. When I use either one of them they seem to stop the copy from happening at all.

What am I doing wrong? Is there a better way to do this?

Thanks very much.

sdexp
  • 756
  • 4
  • 18
  • 36
  • @tripleee Not exactly a duplicate because OP found out the `--parents` option of `cp`. His problem is actually to get rid of the first path level when copying the file. – oliv Jun 08 '18 at 09:57
  • There are multiple answers there which solve this particular aspect, including `rsync` and `tar`. – tripleee Jun 08 '18 at 10:02
  • The answers I have found, including the one you mention, are just a simple copy. I only want to copy certain files. As I do not have much bash experience, you may be right that I just need to do a simple copy of the whole directory then do a selective `rm` in `find` instead. – sdexp Jun 08 '18 at 10:08

1 Answers1

2

Given the following variables:

pathtofolder="/tmp/test" 
pathtoarchive="/var/www/website/archives" 

You could use this:

 find "$pathtofolder" -type f -mmin +"$timeinmins" -exec bash -c 'dir="$2/$(sed "s,^$3,,;s,/[^/]\+$,," <<< "$1")"; mkdir -p "$dir"; cp -v "$1" "$dir"' _ {} "$pathtoarchive" "${pathtofolder}/folders/" \;

sed is used to make the the target directory and assign it to the variable dir. The command removes the first level directory and the name from the filename found by find.

mkdir -p will create the target directory and will not complain if the directory already exist.

Once the directory is created, the copy is done.

oliv
  • 12,690
  • 25
  • 45
  • 1
    Thanks very much. The code is more complicated than I was expecting. Would the number of directories make a difference to the code? E.g. `pathtofolder=/var/www/website/laravel/folder` and `pathtoarchive=/var/www/website/laravel/archives`. – sdexp Jun 08 '18 at 09:42
  • 1
    Am I using the right approach? Would it be simpler to split it into two to find the older files first then I think I could just use a `cp -a`, or I could do the copy in a simpler way. – sdexp Jun 08 '18 at 09:53
  • 1
    @sdexp It shouldn't make any difference, but since your source and target directories share the same path, it might be easier to `/var/www/website/laravel` and do the `find` command from there. – oliv Jun 08 '18 at 09:54
  • 1
    @sdexp Another approach is to use `rsync` – oliv Jun 08 '18 at 09:58
  • 1
    Thank you very much. Unfortunately, I am still getting `archives/var/www` when I try your method and I'm very far from being able to debug. It might be a lot easier to use `rsync`, like you say, and just copy all files over. Then only delete the files that are too old. – sdexp Jun 08 '18 at 10:01