LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Software (https://www.linuxquestions.org/questions/linux-software-2/)
-   -   shell script, rsync wrapper, space in path (https://www.linuxquestions.org/questions/linux-software-2/shell-script-rsync-wrapper-space-in-path-930395/)

ezekieldas 02-20-2012 05:34 PM

shell script, rsync wrapper, space in path
 
I've been using this script in various forms for years now. It has a 'bad habit' as you'll see below. I think the time has come to make a significant change with the way I pass args to the main program but I'm unsure how to do that, and I'd like to understand technically why another method would work better.

Here's are just the critical snippets:

Code:

RSYNCARGS="-e ssh --delete -a -v --iconv=UTF-8,UTF8-MAC --exclude /var/lib/munin \
 --exclude /var/foo bar --rsync-path=/usr/local/bin/rsync"

for i in $FOO
do
 rsync $RSYNCARGS $i $TARGET_HOST:$TARGET_DIR1 >> $RSYNCLOG 2>&1
done

The critical part here is the 2nd 'exclude' that involves a space in the path. I've tried a variety of escapes, quotes, etc. (including \"/var/foo bar\") around the path but nothing works. I think these hacks didn't work partly because I'm passing all that stuff as a string. I'm thinking it would be best to just pass it all as an arg (eg, LSL='ls -l').

Any suggestions would be welcome. I'd like to better understand what would be best in terms of setting the value as a string, as a command, and whether using ${RSYNCARGS} would be helpful.

Cheers,
-zeek

bigrigdriver 02-20-2012 05:47 PM

The usual method to handle spaces in file names is to escape the space, like so:
--exclude /var/foo\ bar

Note the space between the \ and bar.

ezekieldas 02-20-2012 05:57 PM

Thanks --I did try that and wound up with something like: 'rsync: link_stat "/path/to/bar" failed: No such file or directory (2)

I believe the problem is how the args are passed as a string.

ntubski 02-20-2012 06:14 PM

Quote:

Originally Posted by ezekieldas
I think these hacks didn't work partly because I'm passing all that stuff as a string. I'm thinking it would be best to just pass it all as an arg (eg, LSL='ls -l').

You could use a function:

Code:

RSYNC() {
 rsync -e ssh --delete -a -v --iconv=UTF-8,UTF8-MAC --exclude /var/lib/munin \
 --exclude '/var/foo bar' --rsync-path=/usr/local/bin/rsync "$@"
}

for i in $FOO
do
 RSYNC "$i" "$TARGET_HOST:$TARGET_DIR1" >> "$RSYNCLOG" 2>&1
done

or an array:
Code:

RSYNCARGS=(-e ssh --delete -a -v --iconv=UTF-8,UTF8-MAC --exclude /var/lib/munin \
 --exclude '/var/foo bar' --rsync-path=/usr/local/bin/rsync)

for i in $FOO # FOO might be better as an array as well: "${FOO[@]}"
do
 rsync "${RSYNCARGS[@]}" "$i" "$TARGET_HOST:$TARGET_DIR1" >> "$RSYNCLOG" 2>&1
done

and get into the habit of quoting your variables.

ezekieldas 02-20-2012 07:33 PM

ntubski --thanks. Turning this into a function did the trick. Important thing to remember here is including "$@" when something follows :-)

omgs 02-21-2012 02:32 AM

I think the initial approach just needed to double quote the variable:
Code:

RSYNCARGS="-e ssh --delete -a -v --iconv=UTF-8,UTF8-MAC --exclude /var/lib/munin \
 --exclude /var/foo bar --rsync-path=/usr/local/bin/rsync"

for i in $FOO
do
 rsync "$RSYNCARGS" $i $TARGET_HOST:$TARGET_DIR1 >> $RSYNCLOG 2>&1
done

Double quoting the rest of variables, if they don't contain any spaces, looks unnecessary, but if you find problems, quote them, too.

ntubski 02-21-2012 05:52 PM

Quote:

Originally Posted by omgs (Post 4607967)
I think the initial approach just needed to double quote the variable:

Nope, doesn't work:
Code:

~/tmp$ cat ~/bin/args.sh # a useful script to understand shell arg passing
#!/bin/sh
printf '{%s}\n' "$@"
~/tmp$ args.sh 1 2 3
{1}
{2}
{3}
~/tmp$ args.sh file1 "file with spaces" # suppose we want to pass 2 arguments, like this
{file1}
{file with spaces}
~/tmp$ ARGS="file1 file with spaces"
~/tmp$ args.sh $ARGS # unquoted variable doesn't work
{file1}
{file}
{with}
{spaces}
~/tmp$ args.sh "$ARGS" # quoted variable doesn't work
{file1 file with spaces}
~/tmp$ ARGS="file1 'file with spaces'"
~/tmp$ args.sh $ARGS # variable with quotes inside doesn't work
{file1}
{'file}
{with}
{spaces'}
~/tmp$ args.sh "$ARGS" # quoted variable with quotes inside doesn't work
{file1 'file with spaces'}
~/tmp$ passargs() { args.sh file 'file with spaces' ; }
~/tmp$ passargs # using a function works
{file}
{file with spaces}
~/tmp$ ARGS=(file1 'file with spaces')
~/tmp$ args.sh "${ARGS[@]}" # using a quoted array works
{file1}
{file with spaces}

Quote:

Double quoting the rest of variables, if they don't contain any spaces, looks unnecessary, but if you find problems, quote them, too.
I favour a policy of quoting unless you're certain you won't have problems, eg value can only be an integer anyway.


All times are GMT -5. The time now is 12:13 PM.