Supposed I have directory structure like
src/
src/a/
src/a/1.ocf
src/a/1.pdf
src/a/1.txt
src/b/
src/b/2.ocf
src/b/2.pdf
src/b/2.xls
src/c/
src/c/3.doc
src/c/3.ocf
src/c/3.txt
src/d/
Then, I just want to synchronize only files with extension *.txt. So, I tried to use command like:
#rsync -avvH --include="*/" --include="*.txt" --exclude="*" src/ dst/
sending incremental file list
./
a/
a/1.txt
b/
c/
c/3.txt
d/
Unfortunately, this command not only synchronize *.txt file but also all directory. I don't want directory 'b' and 'd' be synchronized because it not contain file *.txt
Is there simple way to do that?
The option you're looking for is -m to prune empty directories:
rsync -avvHm --include="*/" --include="*.txt" --exclude="*" src/ dst/
Related
I have a script that is running to rsync. I set up --exclude but its ignoring and syncing those folder anway.
set -x;
cd $(dir_name $0);
dest="/home/pi/bash_scripts_2/"
export RSYNC_RSH="ssh -q";
#excluding html and man folders
for dir in html man; do
rsync -hav ./$dir/ --exclude 'html/' ./$dir/ $dest$dir/;
rsync -hav ./$dir/ --exclude 'man/' ./$dir/ $dest$dir/;
done
Your loop is doing four things.
First loop:
rsync html/ to dest/html excluding html/ (nothing copied)
rsync html/ to dest/html excluding man/ (html is copied to dest/html)
Second loop:
rsync man/ to dest/man excluding html/ (man is copied to dest/man)
rsync man/ to dest/man excluding man/ (nothing copied)
So overall you're copying both folders.
You shouldn't be passing either html or man as arguments if you don't want them copied.
Consider the following test setup:
mkdir -p src{/html,/man,/do-copy-me} dest
touch src/copy-me src/{html,man}/dont-copy-me src/do-copy-me/yes-really
...given it, this works:
rsync -hav --exclude=html --exclude=man src/. dest/.
Note that we aren't passing html or man as explicit arguments, but the parent directories that contain them.
You'll observe that dest properly contains do-copy-me/yes-really, do-copy-me, but not html or man.
I think all I had to do was remove the / from the html/. Using the . because I do a cd to the current directory. Still have to hardcode the dest directory. But this seems to work. will try to use --exclude-from 'filename.txt' To clean up the code. Thanks for all help.
cd $(dir_name $0);
dest="/home/pi/bash_scripts_2/"
export RSYNC_RSH="ssh -q";
for dir in html man whatever; do
rsync -hav --exclude 'html' --exclude 'man' --exclude 'whatever' . $dest;
done
I need a way to recursively iterate through a directory and copy contents over to another directory following the same directory structure.
For instance, I have the below:
src1/
dir1/
sub-dir1.1/
file1.1
dir2/
sub-dir2.1/
file1
Now, I have another directory elsewhere, which has a similar structure as the above but with less/more files + directories.
src2/
dir1/
sub-dir1.1/
file1.1
file1.2
dir2/
dir3/
file4
I need to copy all contents over from src1 to src2 including all sub-directories under dir1 and dir2. Is there a way to do rather than drilling down to each file under N subdirectories and copying files?
I tried using a "cp -r" but it gives me a "cp: will not overwrite just-created"
Thanks for any insight into this.
The rsync command is well suited to this.
Something like this might achieve what you want:
rsync -av src1/ src2/
Try using the -n flag to begin with to run it in "dry-run" or test mode. This shows you what files it will copy without actually making any changes.
Try rsync -aing the two folders
I have two directories structured as follows:
dir1/a/file1
dir1/a/b/file2
dir1/a/c/d/file3
and
dir2/a/file4
dir2/a/b/file5
dir2/a/c/d/file6
I want to copy all the files in the subdirectories under dir1 to dir2, but keep the files that are currently in dir2, in other words I want to resulting structure to look like:
dir2/a/file1
dir2/a/file4
dir2/a/b/file2
dir2/a/b/file5
dir2/a/c/d/file3
dir2/a/c/d/file6
Is there a simple way to do this using bash?
You could start with
cd dir1
cp -rpuv * ../dir2/
Before:
$ find dir2/
dir2/
dir2/a
dir2/a/file4
dir2/a/c
dir2/a/c/d
dir2/a/c/d/file6
dir2/a/b
dir2/a/b/file5
After:
$ find dir2/
dir2/
dir2/a
dir2/a/file1
dir2/a/file4
dir2/a/c
dir2/a/c/d
dir2/a/c/d/file3
dir2/a/c/d/file6
dir2/a/b
dir2/a/b/file2
dir2/a/b/file5
Note that -p preserves permissions, -v make copy verbose and -u only updates files (doing what the question suggests: keep the files already in dir2)
trying to rsync files of certain extension(*.sh), but the bash script below still transfer all the files, why?
from=/home/xxx
rsync -zvr --include="*.sh" $from/* root#$host:/home/tmp/
You need to add a --exclude all and it has to come after the --include
rsync -zvr --include="*.sh" --exclude="*" $from/* root#$host:/home/tmp/
--include is for which files you want to not --exclude. Since you haven't excluded any in future arguments, there's no effect. You can do:
from=/home/xxx
rsync -zvr --include="*.sh" --include="*/" --exclude="*" "$from" root#$host:/home/tmp/
To recursively copy all .sh files (the extra --include to not skip directories that could contain .sh files)
On thing to add, at least on my machines (FreeBSD and OS X), this does not work:
rsync -aP --include=*/ --include=*.txt --exclude=* * /path/to/dest
but this does:
rsync -aP --include=*/ --include=*.txt --exclude=* . /path/to/dest
Yes, wildcarding the current directory seem to override the exclude.
I fixed the problem changing --exclude=* by --exclude=*.*, I understand that * exclude folder where include files are.
I found a solution for my question in Windows but I'm using Ubuntu: How to copy a directory structure but only include certain files using Windows batch files?
As the title says, how can I recursively copy a directory structure but only include some files? For example, given the following directory structure:
folder1
folder2
folder3
data.zip
info.txt
abc.xyz
folder4
folder5
data.zip
somefile.exe
someotherfile.dll
The files data.zip and info.txt can appear everywhere in the directory structure. How can I copy the full directory structure, but only include files named data.zip and info.txt (all other files should be ignored)?
The resulting directory structure should look like this:
copy_of_folder1
folder2
folder3
data.zip
info.txt
folder4
folder5
data.zip
Could you tell me a solution for Ubuntu?
$ rsync --recursive --include="data.zip" --include="*.txt" --filter="-! */" dir_1 copy_of_dir_1
To exclude dir3 regardless of where it is in the tree (even if it contains files that would match the --includes):
--exclude 'dir3/' (before `--filter`)
To exclude dir3 only at at specific location in the tree, specify an absolute path, starting from your source dir:
--exclude '/dir1/dir2/dir3/' (before `--filter`)
To exclude dir3 only when it's in dir2, but regardless of where dir2 is:
--exclude 'dir2/dir3/' (before `--filter`)
Wildcards can also be used in the path elements where * means a directory with any name and ** means multiple nested directories.
To specify only files and dirs to include, run two rsyncs, one for the files and one for the dirs. The problem with getting it done in a single rsync is that when you don't include a dir, rsync won't enter the dir and so won't discover any files in that branch that may be matching your include filter. So, you start by copying the files you want while not creating any dirs that would be empty. Then copy any dirs that you want.
$ rsync --recursive --prune-empty-dirs --include="*.txt" --filter="-! */" dir_1 copy_of_dir_1
$ rsync --recursive --include '/dir1/dir2/' --include '/dir3/dir4/' --filter="-! */" dir_1 copy_of_dir_1
You can combine these if you don't mind that your specified dirs don't get copied if they're empty:
$ rsync --recursive --prune-empty-dirs --include="*.txt" --include '/dir1/dir2/' --include '/dir3/dir4/' --filter="-! */" dir_1 copy_of_dir_1
The --filter="-! */" is necessary because rsync includes all files and folders that match none of the filters (imagine it as an invisible --include filter at the end of the list of filters). rsync checks each item to be copied against the list of filters and includes or excludes the item depending on the first match it finds. If there's no match, it hits that invisible --include and goes on to include the item. We wanted to change this default to --exclude, so we added an exclude filter (the - in -! */), then we negate the match (!) and match all dirs (*/). Since this is a negated match, the result is that we allow rsync to enter all the directories (which, as I mentioned earlier, allows rsync to find the files we want).
We use --filter instead of --exclude for the final filter because --exclude does not allow specifying negated matches with the ! operator.
I don't have a beautiful one liner, but since nobody else has answered you can always:
find . -name 'file_name.extension' -print | cpio -pavd /path/to/receiving/folder
For each specific file after copying the directories.
(Make sure you're in the original folder first, of course! :) )
Here is a one-liner using rsync:
rsync -a -f"+ info.txt" -f"+ data.zip" -f'-! */' folder1/ copy_of_folder1/
If you already have a file list, and want a more scalable solution
cat file.list | xargs -i rsync -a -f"+ {}" -f'-! */' folder1/ copy_of_folder1/
cp -pr folder1 copy_of_folder1; find copy_of_folder1 -type f ! \( -name data.zip -o -name info.txt \) -exec rm -f {} \;
first time : copy entirely folder1 to copy_of_folder1
second time : erase all files differents from data.zip and
info.txt
At the end, you have your complete structure with only the file data.zip and info.txt