Bash – Passing multiple of arguments with whitespaces through a script to ssh

arraybashquotingshell-scriptssh

I want to remove multiple files from remote server. I have all files under one array in a script and I call other script which will remove files.

Let output of "${b[@]}" is:

/mnt/DataBK/BackupDropwizardLogs_2015-12-17_04-00-01.tar.gz
/mnt/DataBK/BackupDropwizardLogs_2015-12-17_04-30-01.tar.gz
/mnt/DataBK/BackupDropwizardLogs_2015-12-17_05-00-02.tar.gz

script which will remove file is:

#!/bin/bash  
file="$1"  
sshpass -p 'password' ssh user@192.168.3.3 "echo "$file""

while calling bash /tmp/1.sh "'${b[@]}'" I get error

bash: -c: line 0: unexpected EOF while looking for matching `''  
bash: -c: line 1: syntax error: unexpected end of file

And while calling bash /tmp/1.sh "${b[@]}" it assigns only one file to file variable.
/mnt/DataBK/BackupDropwizardLogs_2015-12-17_04-00-01.tar.gz

Can someone please tell me how to assign value of array containing spaces to file variable in above script.

UPDATE:: It worked by setting declare -a file=("$@") in other script. But what if want to send more parameter rather than only array?

Best Answer

sshpass -p 'password' ssh user@192.168.3.3 "some_cmd $(printf '%q ' "$@")"
sshpass -p 'password' ssh user@192.168.3.3 "f() { for i; do some_cmd "$i"; done; }; f $(printf '%q ' some_cmd "$@")"

According to sshpass manpage,

sshpass [-ffilename|-dnum|-ppassword|-e] [options] command arguments

Therefore you should be able to pass all of "$@" into the ssh command, like:

sshpass -p 'password' ssh user@192.168.3.3 printf '%q\n' "$@"

Since your target command may not be able to handle such argument processing, we can hack this around:

sshpass -p 'password' 'k(){ for i; do echo $i; done; }; k' "$@"

Let's test with some whitespaces...

set -- 'foo bar' $'lorem\nipsum\td'
# paste that two lines.. Since I don't have sshpass installed, just using ssh.

ssh apparently messed up. Let's plug some faked shell in and see what happened..

#!/bin/bash
# /bin/mysh
# someone:x:1000:1000:FOo,,Bar,:/home/foo:/bin/mysh
printf '%q ' bash "$@"; echo;
exec bash -xv --norc "$@";

Hmm. Let's try.

bash -c $'printf %q\\n foo bar lorem\nipsum\td'
printf %q\n foo bar lorem
+ printf %qn foo bar lorem
ipsum   d
+ ipsum d
bash: line 1: ipsum: command not found

So apparently ssh simply concatenated those things together with spaces. Not cool.

Let's pre-escape it on our side with printf '%q ', and you will get the TL; DR answer. Now you can figure out about the EOF and -c failure too.

Note: I am not sure if ssh does the -c thing differently among versions. You may need to try this yourself. At least this is true for OpenSSH 7.1 (ssh.c:955-969).

Related Question