Help Shell script to pass variables to rsync
Solution 1
The problem is that you need to quote the file names, but you can't do all that using strings because it will pass all the file names through to rsync as one long string with quotes inside the string (and not individual file string parameters).
The variable $@ is an array in Bash. You need to convert it into a new array when sending to the rsync.
LOCATION="/media/WD100/"
all_files=()
for file in "$@"; do
all_files+=(":\"$LOCATION$file\"")
done
rsync --progress --inplace --append-verify -ave ssh username@homeserver"${all_files[@]}" .
Solution 2
Use:
# prepend "$location" to each element of the `"$@"` array:
for file do
set -- "$@" "$location/$file"
shift
done
rsync ... -0 --files-from=<(printf '%s\0' "$@") user@host: .
Or:
rsync ... -0 --files-from=<(
for file do
printf '%s\0' "$location/$file"
done) user@host: .
to be on the safe side.
That passes the list of files as a NUL delimited list via a named pipe to rsync
.
Related videos on Youtube
Sepero
Updated on September 18, 2022Comments
-
Sepero over 1 year
I'm trying to create a simple wrapper shell script for rsync. When I send file names to my script, rsync can never seem to identify the correct location. The file names have spaces in them. I've tried a dozen different variations using quotes, double quotes, backslashed quotes, and using the rsync -s --protect-args flag. I'm finally out of ideas. Here is a simplified version of my script.
#!/bin/bash # Example usage: # pull.sh "file 1" "file 2" LOCATION="/media/WD100" all_files="" for file in "$@"; do all_files="$all_files:\"$LOCATION/$file\" " done # Pull the given files from homeserver to my current directory. rsync --progress --inplace --append-verify -ave ssh username@homeserver"$all_files" .
Should I be writing this differently? How do make this script work?
UPDATE:
I changed my script to try to reflect Chazelas's answer, but it still seems not to work. Here is my new code:
#!/bin/bash # Example usage: # pull.sh "file 1" "file 2" LOCATION="/media/WD100" all_files="" for file in "$@"; do all_files="$all_files\"$LOCATION/$file\" " done rsync --progress --inplace --append-verify -0 --files-from=<(printf '%s\0' "$all_files") -ave ssh username@homeserver: .
Running it gives me the standard "usage" output, with this error at the end.
rsync error: syntax or usage error (code 1) at options.c(1657) [server=3.0.9] rsync: connection unexpectedly closed (0 bytes received so far) [Receiver] rsync error: error in rsync protocol data stream (code 12) at io.c(605) [Receiver=3.0.9]
-
Admin over 10 yearsStephane's answer should work. It is literally just a one liner, no need for the
for
loop, just use$@
directly inprintf
.
-
-
Sepero over 10 yearsThanks for your help Chazelas. I tried to implement your solution, but without success. I've updated the OP to explain.
-
Stéphane Chazelas over 10 years@Sepero, it's the
"$@"
array that's meant to be passed toprintf
here, see my edit if you want to prepend something to each element of that array. -
Sepero over 10 yearsI think there is a misunderstanding. I'm not "copying all the contents of WD100". The variable $all_files represents all the file names passed to the shell script, not all the files in WD100.