Assigning variables inside remote shell script execution over SSH [duplicate] - linux

This question already has answers here:
is it possible to use variables in remote ssh command?
(2 answers)
Closed 6 years ago.
I am trying to execute some shell script on a remote server via SSH.
Given below is a code sample:
ssh -i $KEYFILE_PATH ubuntu#$TARGET_INSTANCE_IP "bash" << EOF
#!/bin/bash
cat /home/ubuntu/temp.txt
string=$(cat /home/ubuntu/temp.txt )
echo $string
EOF
cat prints the expected result but
$string prints nothing.
How do I store the return value of cat in a variable?

You need to make the content of Here doc literal otherwise they will be expanded in the current shell, not in the desired remote shell.
Quote EOF:
ssh .... <<'EOF'
...
...
EOF

You should be able to simply do this:
ssh -i $KEYFILE_PATH ubuntu#$TARGET_INSTANCE_IP "bash" <<'_END_'
cat /home/ubuntu/temp.txt
string=$(cat /home/ubuntu/temp.txt)
echo $string
_END_
<<'_END_' ... _END_ is called a Here Document literal, or "heredoc" literal. The single quotes around '_END_' prevent the local shell from interpreting variables and commands inside the heredoc.

The intermediate shell is not required (assuming you use bash on the remote system).
Also you dont have to use an intermediate HERE-DOC. Just pass a multiline Command:
ssh -i $KEYFILE_PATH ubuntu#$TARGET_INSTANCE_IP '
cat /home/ubuntu/temp.txt
string=$(cat /home/ubuntu/temp.txt )
echo $string
'
Note I am using single quotes to prevent evaluation on the local shell.

Related

ssh and execute several commands as another user through a heredoc [duplicate]

This question already has answers here:
Usage of expect command within a heredoc
(1 answer)
Pass commands as input to another command (su, ssh, sh, etc)
(3 answers)
Closed 4 years ago.
I have a script that I need to execute through ssh as another use, is there a way to pass whole script like this:
ssh -t user#server.com sudo -u user2 sh -c << EOF
cd /home
ls
dir=$(pwd)
echo "$dir"
echo "hello"
....
EOF
Returns: sh: -c: option requires an argument
ssh'ing and sudo'ing separately is not an option and putting .sh file directly on the machine is not possible.
sh -c requires a command string as the argument. Since you are reading the commands from standard input (through heredoc), you need to use sh -s option:
ssh -t user#server.com sudo -u user2 sh -s << 'EOF'
cd /home
ls
dir=$(pwd)
echo "$dir"
echo "hello"
...
EOF
From man sh:
-c
string If the -c option is present, then commands are read from string. If there are arguments after the string, they are assigned to the positional parameters, starting with $0.
-s
If the -s option is present, or if no arguments remain after option processing, then commands are read from the standard input. This option allows the positional parameters to be set when invoking an interactive shell.
Need to quote the heredoc marker to prevent the parent shell from interpreting the content.

Unable to use local and remote variables within a heredoc or command over SSH

Below is an example of a ssh script using a heredoc (the actual script is more complex). Is it possible to use both local and remote variables within an SSH heredoc or command?
FILE_NAME is set on the local server to be used on the remote server. REMOTE_PID is set when running on the remote server to be used on local server. FILE_NAME is recognised in script. REMOTE_PID is not set.
If EOF is changed to 'EOF', then REMOTE_PID is set and `FILE_NAME is not. I don't understand why this is?
Is there a way in which both REMOTE_PID and FILE_NAME can be recognised?
Version 2 of bash being used. The default remote login is cshell, local script is to be bash.
FILE_NAME=/example/pdi.dat
ssh user#host bash << EOF
# run script with output...
REMOTE_PID=$(cat $FILE_NAME)
echo $REMOTE_PID
EOF
echo $REMOTE_PID
You need to escape the $ sign if you don't want the variable to be expanded:
$ x=abc
$ bash <<EOF
> x=def
> echo $x # This expands x before sending it to bash. Bash will see only "echo abc"
> echo \$x # This lets bash perform the expansion. Bash will see "echo $x"
> EOF
abc
def
So in your case:
ssh user#host bash << EOF
# run script with output...
REMOTE_PID=$(cat $FILE_NAME)
echo \$REMOTE_PID
EOF
Or alternatively you can just use a herestring with single quotes:
$ x=abc
$ bash <<< '
> x=def
> echo $x # This will not expand, because we are inside single quotes
> '
def
remote_user_name=user
instance_ip=127.0.0.1
external=$(ls /home/)
ssh -T -i ${private_key} -l ${remote_user_name} ${instance_ip} << END
internal=\$(ls /home/)
echo "\${internal}"
echo "${external}"
END

How do you export local shell variables into a multi-command ssh?

I am trying to ssh to another server in a shell script and run some scripts.
Currently my line looks something like:
ssh user#$SERVER '$(typeset -a >> /dev/null); PROFILE_LOCATION=`locate db2profile| grep -i $INST_NAME| grep -v bak`; . $PROFILE_LOCATION; function1; function2;'
I've tried both ' and " , as well as using a combination of those with \; or ';'
How do I use the variables I have in my current shell script in my ssh into another server and running multiple commands? Thanks!!
If you want function declarations, and your shell is bash, use typeset -p rather than typeset -a (which will provide a textual dump of variables but not functions). Also, you need to actually run that in a context where it'll be locally evaluated (and ensure that your remote shell is something that understands it, not /bin/sh).
The following hits all those points:
evaluate_db2profile() {
local db2profile
db2profile=$(locate db2profile | grep -i "$INST_NAME" | grep -v bak | head -n 1)
[ -n "$db2profile" ] && . "$db2profile"
}
ssh "user#$SERVER" bash -s <<EOF
$(typeset -p)
evaluate_db2profile
function1
function2
EOF
Because <<EOF is used rather than <<'EOF', the typeset -p command is run locally and substituted into the heredoc. (You could also accomplish this by using double rather than single quotes in the one-line formulation, but see below).
Defining evaluate_db2profile locally as a function ensures that typeset -p will emit it in a format that the remote shell can evaluate, without need to be concerned about escaping.
Using bash -s on the remote command line ensures that the shell interpreting your functions is bash, not /bin/sh. If your code is written for ksh, run ksh -s to achieve that same effect.

Bash command substitution on remote host [duplicate]

This question already has answers here:
How to cat <<EOF >> a file containing code?
(5 answers)
Closed 7 years ago.
I'm trying to run a bash script that ssh's onto a remote host and stops the single docker container that is running.
#!/usr/bin/env bash
set -e
ssh <machine> <<EOF
container=$(docker ps | awk 'NR==2' | awk '{print $1;}')
docker stop $container
EOF
However, I get the following error:
stop.sh: line 4: docker: command not found
When I do this manually (ssh to the machine, run the commands) all is fine, but when trying to do so by means of a script I get the error. I guess that my command substitution syntax is incorrect and I've searched and tried all kinds of quotes etc but to no avail.
Can anyone point me to where I'm going wrong?
Use <<'EOF' (or <<\EOF -- quoting only the first character will have the same effect) when starting your heredoc to prevent its expansions from being evaluated locally.
BTW, personally, I'd write this a bit differently:
#!/bin/sh -e
ssh "$1" bash <<'EOF'
{ read; read container _; } < <(docker ps)
docker stop "$container"
EOF
The first read consumes the first line of docker ps output; the second extracts only the first column -- using bash builtins only.

piping a script to ssh, unable to set variable

I expected it to print v=1. Why does this print v=?
cat<<DONE|ssh user#host
v=1
echo v=$v
DONE
On host, bash is the shell.
Your code is equivalent to:
echo "v=1;echo v=$v"|ssh user#host
What you want is:
echo 'v=1;echo v=$v'|ssh user#host
You can achieve this by using cat<<'DONE' instead of cat<<DONE.
Variables are expanded inside heredocs. You need to escape the $ with a \

Resources