I have a test folder with the following structure:

"driveA"
  - "bar - foo"
    - "fileBarFooA"
    - "fileBarFooB"
  - "fileA"
  - "fileB"
  - "fileC"
  - "folder.A"
    - "fileAA"
    - "fileAB"
  - "folderB"
    - "fileBA"
    - "fileBB"

Within a bash shell, I want to rsync driveA's contents into driveB EXCEPT for folder "folder.A", to get a resulting copy that looks like:

"driveB"
  - "bar - foo"
    - "fileBarFooA"
    - "fileBarFooB"
  - "fileA"
  - "fileB"
  - "fileC"
  - "folderB"
    - "fileBA"
    - "fileBB"

At first glance, one approach to do this is by providing a filtered ls on the driveA as an argument into rsync:

rsync -aR -- `ls -F | grep [^folder.A/]` ../driveB

This results in errors and doesn't complete:

filtered rsync first approach error

The problem is folder "bar - foo" doesn't get copied. Looking at the error, we see that one problem is that we're feeding ls -F which outputs non-escaped output of filenames and folders:

:driveA$ ls -F
bar - foo/  
fileA       
fileB       
fileC
folder.A/
folderB/

I haven't found a option in ls to make it output with escape chars, so instead the next thing to try is post-processing with sed - one way is to add escape chars:

:driveA vgani$ ls -F | sed 's/\ /\\\ /g' | grep [^folder.A/]
bar\ -\ foo/
fileA
fileB
fileC
folderB/

Rsyncing with this gives:

:driveA $ rsync -aR `ls -F | sed 's/\ /\\\ /g' | grep [^folder.A/]` ../driveB
rsync: -\: unknown option
rsync error: syntax or usage error (code 1) at /BuildRoot/Library/Caches/com.apple.xbs/Sources/rsync/rsync-51/rsync/main.c(1337) [client=2.6.9]

Oh no, an error (and a 1337 one at that!) This is just due to rsync taking in the -\ part of the folder as a command-line argument, so we can fix that by adding in --:

driveA $ rsync -aR -- `ls -F | sed 's/\ /\\\ /g' | grep [^folder.A/]` ../driveB

enter image description here

So it looks like the same result as not even bothering with adding escape chars.

Another post-processing idea would be to try adding quotation marks instead:

:driveA $ ls -F | sed 's/^/"/g' | sed 's/[^/]$/"/g' | sed 's/\//"\//g'
"bar - foo"/
"file"
"file"
"file"
"folder.A"/
"folderB"/

But this leads to rsync treating the quotations as literal charaters and copies nothing:

:driveA $ rsync -aR -- `ls -F | sed 's/^/"/g' | sed 's/[^/]$/"/g' | sed 's/\//"\//g' | grep [^\"folder.A\"/]` ../driveB
rsync: link_stat "/driveA/"bar" failed: No such file or directory (2)
rsync: link_stat "/driveA/-" failed: No such file or directory (2)
rsync: link_stat "/driveA/foo"/" failed: No such file or directory (2)
rsync: link_stat "/driveA/"file"" failed: No such file or directory (2)
rsync: link_stat "/driveA/"file"" failed: No such file or directory (2)
rsync: link_stat "/driveA/"file"" failed: No such file or directory (2)
rsync: link_stat "/driveA/"folderB"/" failed: No such file or directory (2)
rsync error: some files could not be transferred (code 23) at /BuildRoot/Library/Caches/com.apple.xbs/Sources/rsync/rsync-51/rsync/main.c(996) [sender=2.6.9]

So far I'm stumped, is there a way to feed rsync contents of ls without choking on hyphen characters?

up vote 1 down vote accepted

Rsync has an exclude option. You should be able to achieve this with:

cd /path/to/driveA
rsync -avWxP --exclude=folder.A . /path/to/driveB/
  • A bit shocked i failed to notice that in the man pages. thanks! – Vivek Gani Nov 13 '16 at 0:51
  • 1
    @VivekGani, you might want to read the less man page—less is the default pager for man. In particular, there is a "search" command (type /). Also, some tips. – Wildcard Nov 13 '16 at 0:57
  • Thanks, aware of using less, think i was using the wrong search term (think I was searching for "ignore" instead of "exclude") at the time. – Vivek Gani Nov 13 '16 at 3:56

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.