[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: rsync --delete



On Sat, 17 Oct 2020 at 19:30, <tomas@tuxteam.de> wrote:
> On Fri, Oct 16, 2020 at 05:09:42PM -0500, Mike McClain wrote:

> > A section of the backup script is so:
> > Params=(-a --inplace --delete);

Using an array here is actually best practice. It will handle most
requirements in a less fragile manner than using a string.

> If you want to have the whole array (space-separated) expanded, you'll
> have to do ${Params[@]}, as Will notes.

Correct. Except it should be quoted:
"${Params[@]}"               see [1] below

> Or -- much better -- don't use arrays here. Whoever wrote that script
> comes from Virtual Basic or Java or something similar. Arrays in shells
> may have their places, but this ain't one of those.

Actually, it is an ideal place to use an array. Whoever wrote
that script shows some knowledge of best practice.

The thorough explanation is found here:
http://mywiki.wooledge.org/BashGuide/Arrays

To take a selection of relevant quotes from that page:
"""
Strings are without a doubt the most used parameter type.
But they are also the most misused parameter type.
It is important to remember that a string holds just one element.
[...]
when you put multiple items in a single string, these multiple
items must be somehow delimited from each other.
[...]
The only safe way to represent multiple string elements
in Bash is through the use of arrays.
"""

It's obvious that in the OP example, the option arguments
are multiple, individual elements.

If they are all smashed together into a string, there's an assumption
that they are separated by whitespace, and that the shell's
whitespace processing will magically separate them.
Well, sometimes that works, and sometimes it doesn't.

For example, it won't work with the rsync option
--exclude=PATTERN
if the desired PATTERN contains whitespace.

Using an array is capable of preserving individual
arguments, without relying on whitespace to do so.

> Simply do:
>   Params="-a --inplace --delete"
> then
>   /usr/bin/rsync $Params [...]

[1] Testing that code at shellcheck.net:
  #!/bin/bash
  Params="-a --inplace --delete"; echo $Params

gives the recommendation regarding $Params:
"Double quote to prevent globbing and word splitting".

Explained in detail there, or at:
http://mywiki.wooledge.org/BashGuide/Practices#Quoting

And here:
http://mywiki.wooledge.org/BashGuide/Parameters
"""
You should always keep parameter expansions properly quoted.
The only good PE, is a quoted PE.
"""

This advice is given by shell-scripting experts because
it handles almost all of the required cases, instead of
just most of them, fingers crossed.
A lot of suboptimal advice on shell scripting bounces
around the net, even amongst smart developers.
The people who are dedicated, expert shell scripters wrote
shellcheck, and write the best guides that I have linked.
I am just reproducing the advice that they offer, in the hope
that it helps people. Of course there are various ways to do
things, and some are easier and less fragile than others,
but if you spend time and take an interest in their
wisdom and experience, this is what they will recommend.

The familiar construct "$@" is an array, widely used, to keep
all the command line arguments separate, even if they
contain whitespace. Arrays like "${Params[@]}" provide
exactly the same benefits.


Reply to: