On recent versions of find
(e.g. GNU 4.4.0) you can use the -newermt
option. For example, to find all files that have been modified on the 2011-02-08
$ find /var/www/html/dir/ -type f -name "*.php" -newermt 2011-02-08 ! -newermt 2011-02-09
Also note that you don't need to pipe into grep to find php files because find can do that for you in the -name
option.
Take a look at this SO answer for more suggestions: How to use 'find' to search for files created on a specific date?
Assuming you have your desired files in a text file, you could do something like
while IFS= read -r file; do
echo mkdir -p ${file%/*};
cp /source/"$file" /target/${file%/*}/${file##*/};
done < files.txt
That will read each line of your list, extract the directory and the file name, create the directory and copy the file. You will need to change source
and target
to the actual parent directories you are using. For example, to copy /foo/a/a.txt
to /bar/a/a.txt
, change source
to foo
and target
to bar
.
I can't tell from your question whether you want to copy all directories and then only specific files or if you just want the directories that will contain files. The solution above will only create the necessary directories. If you want to create all of them, use
find /source -type d -exec mkdir -p {} /target
That will create the directories. Once those are there, just copy the files:
while IFS= read -r file; do
cp /source/"$file" /target/"$file"
done
Update
This little script will move all the files modified after September 8. It assumes the GNU versions of find
and touch
. Assuming you're using Linux, that's what you will have.
#!/usr/bin/env bash
## Create a file to compare against.
tmp=$(mktemp)
touch -d "September 8" "$tmp"
## Define the source and target parent directories
source=/path/to/source
target=/path/to/target
## move to the source directory
cd "$source"
## Find the files that were modified more recently than $tmp and copy them
find ./ -type f -newer "$tmp" -printf "%h %p\0" |
while IFS= read -rd '' path file; do
mkdir -p "$target"/"$path"
cp "$file" "$target"/"$path"
done
Strictly speaking, you don't need the tmp file. However, this way, the same script will work tomorrow. Otherwise, if you use find's -mtime
, you would have to calculate the right date every day.
Another approach would be to first find the directories, create them in the target and then copy the files:
Create all directories
find ./ -type d -exec mkdir -p ../bar/{} \;
Find and copy the relevant files
find ./ -type f -newer "$tmp" -exec cp {} /path/to/target/bar/{} \;
Remove any empty directories
find ../bar/ -type d -exec rmdir {} \;
Best Answer
What is happening here is that when you use the
-R
option tocp
and supply a directory as an argument, it copies everything in that directory. Moreover, this will not preserve the directory structure as any files in lower directories will be copied directly to/tmp/2
. This may be what you want (see X Tian's answer for how to do it this way), but beware if any files have the same name, one will overwrite the other at the detination.To preserve the directory structure, you can use
cpio
:If the
-0
(or equivalent) option is unavailable, you can do this, but be careful none of your file names contains a newline:cpio
should also support the-L
option, although be careful with this as in some cases it can cause an infinite loop.