SSH with heredoc could not modify variable - shell

I use SSH with a heredoc to control remote PC:
val=0
ssh -p 1046 name#10.122.78.99 > result.txt 2>&1 << 'eeooff'
echo $PATH
echo "start"
export vv=333
echo $vv
echo "end"
val=10
eeooff
echo $val
When I check result.txt, I found echo $PATH works, but echo $vv gives nothing. Why? Is setting a variable forbidden when using SSH with a heredoc?
And $val is still 0. How to modify to 10 when using SSH with a heredoc?

Your local shell is the one who have expand $vv, you must escape it like this \$vv.
Excuse my english.

You can also:
ssh -p 1046 name#10.122.78.99 > result.txt 2>&1 << 'eeooff'
This will avoid all variable expansion. Seen here: How to avoid heredoc expanding variables?

Related

bash returns different results when commands are passed to bash shell via ssh or HEREDOC [duplicate]

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

Processing while read line remotely via ssh doesn't fill read variable

I'm trying to remotely process a while read line loop via ssh with the following:
ssh /root/.ssh/id_rsa "while read var; do echo \"- $var -\"; done < /tmp/file; cat /tmp/file"
/tmp/file exists remotely. Output of the command should be:
- /tmp -
- /var -
/tmp
/var
But output actually is:
- -
- -
/tmp
/var
Why doesn't $var get filled here when remotely executed ?
If I happen to connect a console via ssh to the machine and execute the same command, it works as expected.
You should use single quotes or escape the $ in $var. Right now $var is getting substituted before ssh runs.
ssh /root/.ssh/id_rsa 'while read var; do echo "- $var -"; done < /tmp/file; cat /tmp/file'
$var is getting expanded before the ssh because it's inside double quotes. If you make the command you're passing to ssh be in single quotes it won't get expanded, or if you escape the $ you should be set:
ssh /root/.ssh/id_rsa 'while read var; do echo "- $var -"; done < /tmp/file; cat /tmp/file'
or
ssh /root/.ssh/id_rsa "while read var; do echo \"- \$var -\"; done < /tmp/file; cat /tmp/file"

ssh bash receive variable from a remote file

I need to read the variable from a remote file over SSH and compare it. But I get a variable in the wrong format. how to do it correctly?
#!/bin/bash
pass='dpassspass'
user='root#10.10.19.18'
IP="10.2.1.41"
path=/sys/variable/serv
#not work## No such file or directory# write=$(sshpass -p $ovhpass ssh -t $user echo "$IP" > $path)
sshpass -p $pass ssh -t $user << EOF
echo "$IP" > $path
EOF
my_var=$(sshpass -p $pass ssh -t $user "cd /sys_ovh; ./serv.bash")
echo mystart-"$my_var"-myend
read=$(sshpass -p $pass ssh -t $user cat $path)
echo start-"$read"-end
echo start-"$IP"-end
if [ "$read" == "$IP" ]; then
echo "run"
fi
output:
Connection to 10.10.19.18 closed.
-myendt-10.2.1.41
Connection to 10.10.19.18 closed.
-endt-10.2.1.41
start-10.2.1.41-end
Where I make a mistake? How to take data from the SSH?
The vars my_var and read are filled with a string ending with '\r', telling echo to go back to the first column. I think this is a problem with your local script. You can correct that with
tr -d "\r" < myfile > myfile2
Your fundamental problem comes from using unquoted here documents for the commands. You should properly understand in which order the shell interprets these contructs.
ssh remote cmd >file
executes cmd remotely, but first redirects the output from the ssh command to the local file.
ssh remote "cmd >’$file'"
The quotes cause the redirection to be part of the remote command line. The variable file is interpreted first, by the local shell, though.
ssh remote 'cmd >"$file"`
The single quotes prevent the local shell from modifying the command before sending it. Thus, he variable interpolation and the redirection are both handled by the remote shell, in this order.
So your commented-out "not work" command could easily be fixed with proper quoting. However, it will be much more elegant and efficient to use a single remote session, and execute all the commands in one go. Mixing the local variable IP with remote variables calls for some rather elaborate escaping, though. A major simplification would be to pass the value on standard input, so that the entire remote script can be single quoted.
#!/bin/bash
pass='dpassspass'
user='root#10.10.19.18'
IP="10.2.1.41"
result=$(echo "$IP" |
sshpass -p "$pass" ssh -t "$user" '
path=/sys/variable/serv
cat > "$path"
cd /sys_ovh
./serv.bash
cat "$path"')
echo mystart-"${result%$'\n'*}"-myend
echo start-"${result#*$'\n'}"-end
echo start-"$IP"-end
if [ "${result#*$'\n'}" == "$IP" ]; then
echo "run"
fi
The output from the remote shell is two lines; we pick it apart by using the shell's prefix and suffix substitution operators.

SSH heredoc: bash prompt

I am attempting to write a shell script which SSHs into a server and then prompts the user to enter a file/folder.
ssh $SERVER <<EOF
cd downloads/
read -e -p "Enter the path to the file: " FILEPATH
echo $FILEPATH
eval FILEPATH="$FILEPATH"
echo "Downloading $FILEPATH to $CLIENT"
EOF
I am using heredoc instead of double quotes after the SSH to execute these commands because my shell script is rather large and I don't want to be escaping every double quote.
When I was using double quotes, the prompt worked fine. However, now that I am using heredoc, the prompt no longer works.
What can I do to get the prompt to work with heredoc? And if not, is there any way I layout my script so that the prompt does work without wrapping everything in double quotes and escaping, like so:
ssh $SERVER "
cd downloads/
read -e -p \"Enter the path to the file: \" FILEPATH
echo $FILEPATH
eval FILEPATH=\"$FILEPATH\"
echo \"Downloading $FILEPATH to $CLIENT\"
exit
"
If you don't need any variables from the client, why not try - and ssh -t might be useful.
export CLIENT=me
CMDS=$(cat <<CMD
cd downloads/
read -e -p "Enter the path to the file: " FILEPATH
echo \$FILEPATH
eval FILEPATH="\$FILEPATH"
echo "Downloading \$FILEPATH to $CLIENT"
CMD
)
ssh localhost -t "$CMDS"
Note that if your only issue with double-quotes is escaping, and you do not plan on
using ' single quotes in your script, then you can ust do this:
ssh -t $SERVER '
# your script, unescaped.
# if you want access to a locally defined variable,
echo "CLIENT is '$CLIENT'."
'
To make it work with a heredoc, it should be sufficient to invoke bash, or whatever shell you want to use on the remote server. Like so:
ssh $SERVER bash <<EOF
cd downloads/
read -e -p "Enter the path to the file: " FILEPATH
echo $FILEPATH
eval FILEPATH="$FILEPATH"
echo "Downloading $FILEPATH to $CLIENT"
EOF
Note that you probably want to escape the $ on FILEPATH, since currently that will be interpolated by the local shell rather than the remote shell.
this works, tab completion on the host works.
var=$(cat<<EOF
read -e -p Path pname;
echo \$pname;
hostname;
echo \$pname;
cd \$pname;
pwd;
touch THIS ;
exit;
EOF
)
ssh -t NODE $var
on mine this creates the file THIS in the prompted for directory.
This one seems to work:
T=$(tty) ; bash <<XXX
echo Hi "$T"
read p <$T
echo p: \$p
echo Bye
XXX

Send a variable to a remote server with ssh

Im trying to do log into a file (in a remote server lets say /home/test/log.txt) what is stored in $var. Im trying with
ssh test#$192.168.1.35 "echo "var" >> /home/test/log.txt"
y also tried
ssh test#$192.168.1.35 "echo "$var" >> log.txt"
but the both didnt work
any help?
You're using double quotes, so the variable expansion will happen locally. You should use single quotes, so that the command gets sent unaltered.
In the same way as echo '$var' gives $var while echo "$var" displays the contents, this way the server sees $var instead of the contents of the local $var.
So:
ssh test#$192.168.1.35 'echo $var >> /home/test/log.txt'
will create a file on the remote computer, with the value of the remote $var in it.
If you do
ssh test#$192.168.1.35 'echo $var' >> /home/test/log.txt
you get a file on the local computer with the value of the remote $var in it.
If you do
ssh test#$192.168.1.35 "echo $var >> /home/test/log.txt"
it stores the value of your local $var in the file on the remote system.
(Also, if it only involves the remote system, you should probably use a shell script, or maybe cron if you want it to happen automatically.)
Try:
ssh test#192.168.1.35 "echo '$var' >> /home/test/log.txt"
Did you try:
ssh test#$192.168.1.35 'echo "$var" >> /home/test/log.txt'
This should work. Assuming var was set on your computer and not the remote.
Here is the correct way to put some text from a linux machine in an already existing file on another linux machine:
echo 'text' | ssh test#$192.168.1.35 'cat >> /remote_file_path'

Resources