4

I have a heredoc that needs to call existing variables from the main script, and set its own variables to use later. Something like this:

count=0

ssh $other_host <<ENDSSH
  if [[ "${count}" == "0" ]]; then
    output="string1"
  else
    output="string2"
  fi
  echo output
ENDSSH

That doesn't work because 'output' doesn't get set to anything.

I tried using the solution from this question:

count=0

ssh $other_host << \ENDSSH
  if [[ "${count}" == "0" ]]; then
    output="string1"
  else
    output="string2"
  fi
  echo output
ENDSSH

It didn't work either. $output got set to "string2" because $count wasn't expanded.

How can I use a heredoc that expands variables from the parent script, and sets its own variables?

user2824889
  • 1,085
  • 5
  • 16
  • 28

3 Answers3

4

You can use:

count=0

ssh -t -t "$other_host" << ENDSSH
  if [[ "${count}" == "0" ]]; then
    output="string1"
  else
    output="string2"
  fi
  echo "\$output"
  exit
ENDSSH

We use \$output so that it is expanded on remote host not locally.

anubhava
  • 761,203
  • 64
  • 569
  • 643
1

It is better not to use stdin (such as by using here-docs) to pass commands to ssh.

If you use a command-line argument to pass your shell commands instead, you can better separate what is expanded locally and what will be executed remotely:

# Use a *literal* here-doc to read the script into a *variable*.
# Note how the script references parameter $1 instead of
# local variable $count.
read -d '' -r script <<'EOF'
  [[ $1 == '0' ]] && output='zero' || output='nonzero'
  echo "$output"
EOF

# The variable whose value to pass as a parameter.
# With value 0, the script will echo 'zero', otherwise 'nonzero'.
count=0

# Use `set -- '$<local-var>'...;` to pass the local variables as
# positional parameters, followed by the script code.
ssh localhost "set -- '$count'; $script"
Community
  • 1
  • 1
mklement0
  • 382,024
  • 64
  • 607
  • 775
0

You can escape the variables as @anubhava said, or, if you get too much variables for the escaping, you can do it in two steps:

# prepare the part which should not be expanded
# note the quoted 'EOF'
read -r -d '' commands <<'EOF'
if [[ "$count" == "0" ]]; then
    echo "$count - $HOME"
else
    echo "$count - $PATH"
fi
EOF

localcount=1
#use the unquoted ENDSSH
ssh me@nox.local <<ENDSSH
count=$localcount # count=1
#here will be inserted the above prepared commands
$commands 
ENDSSH

will print something like:

1 - /usr/bin:/bin:/usr/sbin:/sbin
clt60
  • 62,119
  • 17
  • 107
  • 194