1

I have an issue with a variable rsync parameter. I concat filtered expression on COMPILE_FILTERS variable. Example :

COMPILE_FILTERS='--filter="- js/editor/editorjs/*"'
rsync -a $COMPILE_FILTERS \
  --filter="- *node_modules*" \
  --filter="- .git*" \
  --filter="- /**/.git*" \
  $src $dest

The following response are displayed.

Unknown filter rule: `"-'
rsync error: syntax or usage error (code 1) at exclude.c(927) 
[client=3.1.3]

That strange because interpreter seem to block on the hyphen.

Thanks you in advance if you have an advice.

Vincent
  • 113

1 Answers1

0

There are two issues with your code.

  1. The expansion of $COMPILE_FILTERS is unquoted. This mean that its value, --filter="- js/editor/editorjs/*", will be split into words on whitespace (by default). These words are --filter="- and js/editor/editorjs/*". The words will then undergo filename generation (globbing), but in your case, this would only be an issue if you happened to have a file matching the pattern js/editor/editorjs/*" somewhere.

    The splitting into two words means that rsync will get two arguments, and it fails to properly use the first of these (this is what you error message refers to).

    You solve this issue by double quoting the expansion of the variable.

  2. The string that you save in the variable includes the double quotes. If you double quote the expansion of the variable, you are basically telling rsync to use the filter "- js/editor/editorjs/*" (with double quotes and all). This is because you use single quotes around the string.

    You solve this issue by assigning the correct string to the variable:

    COMPILE_FILTERS=--filter="- js/editor/editorjs/*"
    

    or

    COMPILE_FILTERS='--filter=- js/editor/editorjs/*'
    

End result:

COMPILE_FILTERS='--filter=- js/editor/editorjs/*'
rsync -a "$COMPILE_FILTERS" \
  --filter="- *node_modules*" \
  --filter="- .git*" \
  --filter="- /**/.git*" \
  "$src" "$dest"

Note that I have also quoted the other variables involved in the code.

See also:


If you later decide to include further filters in your variable, make sure to switch to an array (in a shell that supports these):

filters=(
    --filter="- js/editor/editorjs/*"
    --filter="- *node_modules*"
    --filter="- .git*"
    --filter="- /**/.git*"
)

rsync --archive "${filters[@]}" "$src" "$dest"

In shell that don't have named array variables (/bin/sh, dash), you get to type less:

set -- \
    --filter="- js/editor/editorjs/*" \
    --filter="- *node_modules*" \
    --filter="- .git*" \
    --filter="- /**/.git*"

rsync --archive "$@" "$src" "$dest"

You need an array or list to properly handle the separate filter arguments. Trying to combine the multiple filters into a single string would be doable, but way harder, as you have to handle the shell's word splitting and filename globbing properly.

Kusalananda
  • 333,661