How can I run commands in nested SSH connections in Bash? - linux

I need to write a script which will connect to the server and run some utils there.
So, if I want to connect to the server, I do
ssh $server << EOF
run
some
commands
EOF
And it works properly.
But if I want to do nested ssh connection, I'm doing like this:
ssh $server_1 << EOF
ssh $server_2 << EOF
run some commands
EOF
I guess it works properly, but I'm receiving error messages
Do you know how to use "nested" EOFs properly?
I know that I can run
ssh $server 'run|some|commands'
but there are a lot of commands here and I cant write it into a line
Thank you for answers

Use two different "end of here-document" delimiters:
ssh $server_1 << EOF1
ssh $server_2 << EOF2
run some commands
EOF2
EOF1
Or better yet, use an "SSH jump host" like this:
ssh -J $server_1 $server_2 << EOF
run some commands
EOF

Related

Is there a way to automatically answer for user prompt when doing ssh in a shell script without using expect or spawn?

I'm trying to test ssh trust between a linux box against 12 other linux boxes using a shell script and I'm trying to pass user input as 'yes' for the question below automatically.
Are you sure you want to continue connecting (yes/no)?
but the script is failing with error 'Host key verification failed'. I manually executed the ssh command with << EOT on one of the server but the I still get user prompt question. Is there any-other way to pass input value for user prompts automatically while running ssh command?
Note: I cannot use spawn or except do you some system limitation and I cannot install them due to organisations access restrictions.
I tried with the following options but none of them worked for me
[command] << [EOT, EOL, EOF]
echo 'yes'
[EOT, EOL, EOF]
yes | ./script.sh
printf "yes" | ./script.sh
echo "yes" | ./script.sh
./script.sh 'read -p "Are you sure you want to continue connecting (yes/no)?";echo "yes"'
sh```
for server in `cat server_list` ; do
UPPER_MACHINE_NAME=`echo $server | cut -d '.' -f 1`
UPPER_MACHINE_NAME=${UPPER_MACHINE_NAME^^}
ssh -tt user#$UPPER_MACHINE_NAME << EOT
echo 'yes'
touch /usr/Finastra/sshtest.txt
EOT
done
```

How to connect input/output to SSH session

What is a good way to be able to directly send to STDIN and receive from STDOUT of a process? I'm specifically interested in SSH, as I want to do the following:
[ssh into a remote server]
[run remote commands]
[run local commands]
[run remote commands]
etc...
For example, let's say I have a local script "localScript" that will output the next command I want to run remotely, depending on the output of "remoteScript". I could do something like:
output=$(ssh myServer "./remoteScript")
nextCommand=$(./localScript $output)
ssh myServer "$nextCommand"
But it would be nice to do this without closing/reopening the SSH connection at every step.
You can redirect SSH input and output to FIFO-s and then use these for two-way communication.
For example local.sh:
#!/bin/sh
SSH_SERVER="myServer"
# Redirect SSH input and output to temporary named pipes (FIFOs)
SSH_IN=$(mktemp -u)
SSH_OUT=$(mktemp -u)
mkfifo "$SSH_IN" "$SSH_OUT"
ssh "$SSH_SERVER" "./remote.sh" < "$SSH_IN" > "$SSH_OUT" &
# Open the FIFO-s and clean up the files
exec 3>"$SSH_IN"
exec 4<"$SSH_OUT"
rm -f "$SSH_IN" "$SSH_OUT"
# Read and write
counter=0
echo "PING${counter}" >&3
cat <&4 | while read line; do
echo "Remote responded: $line"
sleep 1
counter=$((counter+1))
echo "PING${counter}" >&3
done
And simple remote.sh:
#!/bin/sh
while read line; do
echo "$line PONG"
done
The method you are using works, but I don't think you can reuse the same connection everytime. You can, however, do this using screen, tmux or nohup, but that would greatly increase the complexity of your script because you will now have to emulate keypresses/shortcuts. I'm not even sure if you can if you do directly in bash. If you want to emulate keypresses, you will have to run the script in a new x-terminal and use xdotool to emulate the keypresses.
Another method is to delegate the whole script to the SSH server by just running the script on the remote server itself:
ssh root#MachineB 'bash -s' < local_script.sh

Running Nested Command Lines with HERE

This command myprogram.sh command in CygWin installed with Chocolatey, called from the Windows Command Line, with an alias server01 created at the .ssh folder, everything works fine:
# File myprogram.sh
ssh -p 66622 user#localhost << HERE
ssh server01 << EOF
command1
command2
EOF
HERE
Because i have several servers, i have to build several .sh files for different set of commands, so i have to create a lot of .sh files
But i've been unable to run the same instructions from a single line from the command line. Is that possible, in order to run these chain of instructions from a same place?
#!/bin/bash
array=(server1 server2 server3 .... serverN)
for i in ${array[#]}
do
echo ${i}
ssh -p 66622 user#${i} "command1"
done
you can change the "command1" to "command.sh"

Using 'expect' command to pass password to SSH running script remotely

I need to create a bash script that will remotely run another script on a batch of machines. To do so I am passing a script through SSH.
ssh -p$port root#$ip 'bash -s' < /path/to/script/test.sh
I thought it would use my RSA keys but I am getting error:
"Enter password: ERROR 1045 (28000): Access denied for user 'root'#'localhost' (using password: YES)"
I tried using sshpass to no avail. So my next solution was using expect. I have never used expect before and I'm positive my syntax is way off.
ssh -p$port root#$ip 'bash -s' < /path/to/script/test.sh
/usr/bin/expect <<EOD
expect "password"
send "$spass\n"
send "\n"
EOD
I have root access to all machines and ANY solution will do as long as the code remains within bash. Just keep in mind that this will be done in a loop with global variables ($spass, $ip, $port, etc) passed from a parent script.
You are doing it wrong in two means:
If you want expect to interact with ssh, you need to start ssh from expect script and not before.
If you put the script (/path/to/script/test.sh) to stdin of ssh, you can't communicate with the ssh process any more.
You should rather copy the script to remote host using scp and then run it.
Expect script might look like this:
/usr/bin/expect <<EOF
spawn ssh -p$port root#$ip
expect "password"
send "$Spass\r"
expect "$ "
send "/path/to/script/on/remote/server/test.sh\r"
expect "$ "
interact
EOF
#!/usr/bin/expect
#Replace with remote username and remote ipaddress
spawn /usr/bin/ssh -o StrictHostKeyChecking=no username#IPAddress
#Replace with remote username and remote ipaddress
expect "username#IPAddress's password: "
#Provide remote system password
send "urpassword\n"
#add commands to be executed. Also possible to execute bash scripts
expect "$ " {send "pwd\n"} # bash command
expect "$ " {send "cd mytest\n"}
expect "$ " {send "./first.sh\n"} # bash scripts
expect "$ " {send "exit\n"}
interact

pipe timely commands to ssh

I am trying to pipe commands to an opened SSH session. The commands will be generated by a script, analyzing the results, and sending the next commands in accordance.
I do not want to put all the commands in a script on the remote host, and just run that script, because I am interested also in the status of the SSH process: sending locally the commands allow to "test" whether the SSH connection is alive or not, and get the appropriate return code from the SSH process.
I tried using something along these lines:
$ mkfifo /tpm/commands
$ ssh -t remote </tmp/commands
And from another term:
$ echo "command" >> /tmp/commands
Problem: SSH tells me that no pseudo-tty will be opened for stdin, and closes the connection as soon as "command" terminates.
I tried another approach:
$ ssh -t remote <<EOF
$(echo "command"; while true; do sleep 10; echo "command"; done)
EOF
But then, nothing is flushed to ssh until EOF is reached (in my case, never).
Do any of you have a solution ?
Stop closing /tmp/commands before you're done with it. When you close the pipe, ssh stops reading from it.
exec 7> /tmp/commands. # open once
echo foo >&7 # write multiple times
echo bar >&7
exec 7>&- # close once
You can additionally use ssh -tt to force ssh to open a tty on the remote.

Resources