user3437245
user3437245

Reputation: 347

copy files with the base directory

I am searching specific directory and subdirectories for new files, I will like to copy the files. I am using this:

find /home/foo/hint/ -type f -mtime -2 -exec cp '{}' ~/new/ \;

It is copying the files successfully, but some files have same name in different subdirectories of /home/foo/hint/. I will like to copy the files with its base directory to the ~/new/ directory.

test@serv> find /home/foo/hint/ -type f -mtime -2 -exec ls '{}' \;
/home/foo/hint/do/pass/file.txt
/home/foo/hint/fit/file.txt
test@serv> 

~/new/ should look like this after copy:

test@serv> ls -R ~/new/
/home/test/new/pass/:
file.txt

/home/test/new/fit/:
file.txt
test@serv>

platform: Solaris 10.

Upvotes: 0

Views: 367

Answers (5)

ghoti
ghoti

Reputation: 46856

Since you can't use rsync or fancy GNU options, you need to roll your own using the shell.

The find command lets you run a full shell in your -exec, so you should be good to go with a one-liner to handle the names.

If I understand correctly, you only want the parent directory, not the full tree, copied to the target. The following might do:

#!/usr/bin/env bash

findopts=(
    -type f
    -mtime -2
    -exec bash -c 'd="${0%/*}"; d="${d##*/}"; mkdir -p "$1/$d"; cp -v "$0" "$1/$d/"' {} ./new \;
)

find /home/foo/hint/ "${findopts[@]}"

Results:

$ find ./hint -type f -print
./hint/foo/slurm/file.txt
./hint/foo/file.txt
./hint/bar/file.txt
$ ./doit
./hint/foo/slurm/file.txt -> ./new/slurm/file.txt
./hint/foo/file.txt -> ./new/foo/file.txt
./hint/bar/file.txt -> ./new/bar/file.txt

I've put the options to find into a bash array for easier reading and management. The script for the -exec option is still a little unwieldy, so here's a breakdown of what it does for each file. Bearing in mind that in this format, options are numbered from zero, the {} becomes $0 and the target directory becomes $1...

d="${0%/*}"            # Store the source directory in a variable, then
d="${d##*/}"           # strip everything up to the last slash, leaving the parent.
mkdir -p "$1/$d"       # create the target directory if it doesn't already exist,
cp "$0" "$1/$d/"      # then copy the file to it.

I used cp -v for verbose output as shown in "Results" above, but IIRC it's also not supported by Solaris, and can be safely ignored.

Upvotes: 1

user3437245
user3437245

Reputation: 347

I found a way around it:

cd ~/new/
find /home/foo/hint/ -type f -mtime -2 -exec nawk -v f={} '{n=split(FILENAME, a, "/");j= a[n-1];system("mkdir -p "j"");system("cp "f" "j""); exit}' {} \;

Upvotes: 0

TAq
TAq

Reputation: 101

The problem with the answers by @Mureinik and @nbari might be that the absolute path of new files will spawn in the target directory. In this case you might want to switch to the base directory before the command and go back to your current directory afterwards:

path_current=$PWD; cd /home/foo/hint/; find . -type f -mtime -2 -exec cp --parents '{}' ~/new/ \; ; cd $path_current

or

path_current=$PWD; cd /home/foo/hint/; find . -type f -mtime -2 -exec rsync -R '{}' ~/new/ \; ; cd $path_current

Both ways work for me at a Linux platform. Let’s hope that Solaris 10 knows about rsync’s -R ! ;)

Upvotes: 0

nbari
nbari

Reputation: 26925

Try testing with rsync -R, for example:

find /your/path -type f -mtime -2 -exec rsync -R '{}' ~/new/ \;

From the rsync man:

-R, --relative
              Use  relative  paths.  This  means that the full path names specified on the
              command line are sent to the server rather than just the last parts  of  the
              filenames. 

Upvotes: 0

Mureinik
Mureinik

Reputation: 311468

The --parents flag should do the trick:

find /home/foo/hint/ -type f -mtime -2 -exec cp --parents '{}' ~/new/ \;

Upvotes: 0

Related Questions