5

I have a script parsing a list of servers, looking for some stuff and executing commands if the circumstances are correct. The main server is connecting to them via ssh, executing all commands that are in the EOF statement:

#!/bin/bash

# parsing servers
# defining one local variable $VAR

ssh -T -p 1234 root@"server-ip" "$variable" << 'EOF'
# doing some stuff...
var_result=$(mysql -hhost -uuser '-ppasswort' -Ddatabase -N -e "SELECT something FROM somewhere WHERE value=$VAR;")
EOF

I know the variable can pass through if I remove the single quotes from the EOF, but if i do so the mysql statements wont work and everything breaks.

I know there are ways to transmit a variable, but things with ";" between options wont work for me ( the script tries to execute it as a command )

Any ideas?

Permittivity
  • 87
  • 1
  • 7
  • give some examples of what you want and what you don't... – Jahid May 08 '16 at 18:59
  • i just want to use the local defined variable in the EOF statement, but everything i tried didn't work for me. If i want to echo the variable on the remote server i don't get any results -> so the script doesn't send it. – Permittivity May 08 '16 at 19:02
  • Add your mysql statements to your question. – Cyrus May 08 '16 at 19:19
  • BTW -- if this value is coming from an untrusted source, while my answer is secure against shell injection, it doesn't do anything about SQL injection risks. (I didn't quote the actual mysql command in my answer because I didn't want to do anything that demonstrates bad practices). You might look into whether there's a way to pass a string as a bind variable via the command line -- I once built a PostgreSQL client that could do that, back in the mists of time; I'd *hope* for a way to do that in MySQL too. – Charles Duffy May 09 '16 at 17:24

2 Answers2

15

Use printf %q to escape content in an eval-safe form; after doing so, you can pass them on the command line of the remote shell, and retrieve them via $1, $2, etc. within the remote script:

# put contents of $VAR into $var_str in a format that a shell can interpret
printf -v var_str %q "$VAR"

#                                    v- pass the value on the shell command line
#                                    |           v- keep escaping the heredoc securely
#                                    |           |
ssh -T -p 1234 root@"$host" "bash -s $var_str" <<'EOF'

# retrieve it off the shell command line
var=$1

# ...and use it as you like thereafter.
echo "Remotely using $var"
EOF
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • Charles, I've been using your method with success. But how would I use this method to pass arrays instead of a string? – Twoez Jan 11 '20 at 08:58
  • @Twoez, *multiple* arrays, or just one? A single array is trivial; `printf -v var_str '%q ' "${array[@]}"`, and then `array=( "$@" )`; for more than one, I discuss techniques in a different question -- see the "before bash 4.3" section of https://stackoverflow.com/a/10953834/14122 – Charles Duffy Jan 11 '20 at 15:32
2

How about using EOF without the quote and making the mysql command work:

#!/bin/bash

# parsing servers
# defining one local variable $VAR
VAR=something

ssh -T -p 1234 root@"server-ip" <<EOF
# doing some stuff...
var_result=\$(mysql -hhost -uuser '-ppasswort' -Ddatabase -N -e "SELECT something FROM somewhere WHERE value=$VAR;")
EOF

As Charles Duffy stated, this may produce some security risk.

Another way is to wrap all your codes around single quote:

#!/bin/bash

# parsing servers
# defining one local variable $VAR

ssh -T -p 1234 root@"server-ip" '
# doing some stuff...
var_result=$(mysql -hhost -uuser "-ppasswort" -Ddatabase -N -e "SELECT something FROM somewhere WHERE value='"$VAR"';")
'

In this case you will have to be careful what you substitute your variables for. Better use Charles Duffys' method if you should be concerned about it.

Community
  • 1
  • 1
Jahid
  • 21,542
  • 10
  • 90
  • 108
  • what do you mean by "bash <<'EOF'" ? where do i have to insert "bash" ? after the ssh command? Because that does not work for me. – Permittivity May 08 '16 at 19:09
  • I tried: `export variable="dummy"` but when i did echo inside of the EOF-statement it does not print my variable, just an empty line. – Permittivity May 08 '16 at 19:14
  • alright. thank you for your time. – Permittivity May 08 '16 at 19:28
  • @Jahid, it works, but *badly* -- there's significant security risk, inasmuch as content substituted into script text can perform a shell escape and run arbitrary commands. – Charles Duffy May 08 '16 at 19:42
  • @Jahid, ...in this case, a concrete example of that would be `VAR=';"; touch /tmp/be-glad-i-didnt-rm-rf-HOME; echo "'` – Charles Duffy May 08 '16 at 19:43
  • @CharlesDuffy : yap. How about passing it as a string within a single quote? – Jahid May 08 '16 at 19:56
  • 1
    In the answer as-currently-amended, you're still ending that single-quote for the variable substitution, allowing arbitrary code to be substituted into the remote string. – Charles Duffy May 08 '16 at 19:58
  • 1
    ...also, if you don't start a double-quoted context after ending the single-quotes before the substitution, any spaces substituted in will be subject to word-splitting; whitespace-surrounded globs subject to expansion; etc. – Charles Duffy May 08 '16 at 19:59
  • okay, that fixes the new bugs you introduced with the single-quote situation -- though the shell escape is still there. – Charles Duffy May 08 '16 at 20:09