bash - executing ssh command in a loop - bash

I have the loop:
IFS=','
for host in host1,host2
do
ssh root#$host script.sh
done
When I execute the loop, ssh command works fine for host1, but for host2 I see:
bash: host2: command not found
Could you tell me where can be the problem?

Just like this
for host in host1 host2
do
ssh root#$host script.sh
done

You above script will return an output command like this
ssh root#host1 host2 script.sh
Here host2 is considered as an argument or a command which the shell is not able to recognize and hence you are getting the above error.
Assuming your use case is to run the shell script on both hosts the following script might help you
IFS=', ' read -r -a array <<< host1,host2
for host in ${array[#]}; do ssh root#$host script.sh; done
output command will be similar to below
ssh root#host1 script.sh
ssh root#host2 script.sh

PSSH (https://github.com/lilydjwg/pssh)
Create your file with hosts/ip addresses, then try following:
pssh -h hostfile.txt -l root -i "echo 'hello world'; another_command; exit"
-h = hostfile with ip adddresses
-l = username to use
-i = command to execute on source
-A = for use password

Related

Run shell commands in a remote machine

I would like to know how can I run shell commands in a remote machine.
I tried this:
ssh prdcrm1#${server} "grep -l 'Sometthing' *"
It is working, but I want to run more commands.
Do someone has an Idea?
You can run multiple commands on remote machine like,
Run date and hostname commands:
$ ssh user#host "date && hostname"
Run a script called /scripts/backup.sh
ssh user#host '/scripts/backup.sh'
Run sudo or su command using the following syntax
ssh user#host su --session-command="/sbin/service httpd restart"
ssh -t user#host 'sudo command1 arg1 arg2' ## su syntax ##
Multi-line command with variables expansion
VAR1="Variable 1"
ssh $HOST bash -c "'
ls
pwd
if true; then
echo $VAR1
else
echo "False"
fi
'"
Hope these helps you.

Properly Escape $ in a nested remote command

I would like to execute a command on a remote host from another remote host.
HOST1=host1.domain.tld
HOST2=host2.domain.tld
HOST1 is used to connect to HOST2 and the command executes on HOST2. The remote command depends a variable that is calculated on HOST2.
ssh -A $HOST1 -C "x=wrong; ssh -A $HOST2 -C "x=right; echo \$x""
Strangely, the above returns $x while the next command returns wrong instead of an empty line.
ssh -A $HOST1 -C "x=wrong; ssh -A $HOST2 -C "echo \$x""
Question 1: Why is the first command giving me $x?
Question 2: Keeping the double quotes, how do I have it print right?
Section 1: Literal Answers
...to the question precisely as-asked.
Why is the first command giving me $x?
Keep in mind that this command is executed multiple times, and is thus transformed by multiple shells. That transformation looks something like the following (assuming HOST1 of 1.1.1.1 and HOST2 of 2.2.2.2):
ssh -A 1.1.1.1 -C "x=wrong; ssh -A 2.2.2.2. -C "x=right; echo \$x""
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^
...note the arrows? Those are showing where your quoted regions begin and end: Your quote just before x=right is ending your quote that started before x=wrong!
Thus, this tokenizes to two separate commands, written out with one shell word per line below:
# command one: ssh
ssh \
-A \
1.1.1.1 \
-C \
"x=wrong; ssh -A 2.2.2.2. -C "x=right;
# command two: echo
echo \
\$x""
Keeping the double quotes, how do I have it print right?
Backslash-escape the nested quotes so they don't close the quotes you intend to be outer.
ssh -A $HOST1 -C "x=wrong; ssh -A $HOST2 -C \"x=right; echo \$x\""
Section 2: Best-Practice Alternatives
SSH - ProxyCommand
In practice, don't do this kind of explicit nested SSH invocation at all -- just use the ProxyCommand ssh config option:
ssh \
-o "ProxyCommand ssh $HOST1 netcat -w 120 %h %p' \
"$HOST2" 'x=right; echo "$x"'
Bash - nestable eval-safe quote generation
In general, trying to escape things by hand is much more error-prone than telling the shell to do it for you.
host2_cmd='x=right; echo "$x"'
printf -v host1_cmd '%q ' ssh -A "$HOST2" -C "$host2_cmd"
ssh "$HOST1" bash -s <<<"$host1_cmd"
To demonstrate, we could even do this with a third host in the way:
host3_cmd='x=right; echo "$x"'
printf -v host2_cmd '%q ' ssh -A "$HOST3" -C "$host3_cmd"
printf -v host1_cmd '%q ' ssh -A "$HOST2" -C "$host2_cmd"
ssh "$HOST1" bash -s <<<"$host1_cmd"
This works because in ksh and bash, printf %q quotes a string in such a way that it'll evaluate to its current contents when parsed by that same shell.

Bash While loop is not looping

Im doing a backup script for Mikrotik devices using bash. I want to use a while loop that will read from a file.
The Contents of the file to read from will be like:
1.1.1.1 router1
2.2.2.2 router2
Here is my sample script:
while read -r ip name
do
sshpass -p "pass" ssh -o StrictHostKeyChecking=no export\#$ip "/export;/quit" 2> errors.log >> $name.export
done < iplistandnamefile
The problem is that the script will work for only the 1st IP address on the iplistandnamefile file but will not loop to the 2nd IP.
Any suggestions ?
ssh is eating the rest of the file as it defaults to reading stdin
add -n to the ssh command.
sshpass -p "pass" ssh -no StrictHostKeyChecking=no user#host command_to_run

How to copy echo 'x' to file during an ssh connection

I have a script which starts an ssh-connection.
so the variable $ssh start the ssh connection.
so $SSH hostname gives the hostname of the host where I ssh to.
Now I try to echo something and copy the output of the echo to a file.
SSH="ssh -tt -i key.pem user#ec2-instance"
When I perform a manual ssh to the host and perform:
sudo sh -c "echo 'DEVS=/dev/xvdbb' >> /etc/sysconfig/docker-storage-setup"
it works.
But when I perform
${SSH} sudo sh -c "echo 'DEVS=/dev/xvdb' > /etc/sysconfig/docker-storage-setup"
it does not seem to work.
EDIT:
Also using tee is working fine after performing an ssh manually but does not seem to work after the ssh in the script.sh
The echo command after an ssh of the script is happening on my real host (from where I'm running the script, not the host where I'm performing an ssh to). So the file on my real host is being changed and not the file on my host where I've performed an ssh to.
The command passed to ssh will be executed by the remote shell, so you need to add one level of quoting:
${SSH} "sudo sh -c \"echo 'DEVS=/dev/xvdb' > /etc/sysconfig/docker-storage-setup\""
The only thing you really need on the server is the writing though, so if you don't have password prompts and such you can get rid of some of this nesting:
echo 'DEVS=/dev/xvdb' | $SSH 'sudo tee /etc/sysconfig/docker-storage-setup'

Shell script to grep logs on different host and write the grepped output to a file on Host 1

Shell script needs to
ssh to Host2 from Host1
cd /test/test1/log
grep logs.txt for string error
write the grepped output to a file
and move that file to Host1
This can be accomplished by specifying the -f option to ssh:
ssh user#host -f 'echo "this is a logfile">logfile.txt'
ssh user#host -f 'grep logfile logfile.txt' > locallogfile.txt
cat locallogfile.txt
An example using a different directory and cd changing directories to it:
ssh user#host -f 'mkdir -p foo/bar'
ssh user#host -f 'cd foo/bar ; echo "this is a logfile">logfile.txt'
ssh user#host -f 'cd foo/bar ; echo "this is a logfile">logfile.txt'
ssh user#host -f 'cd foo/bar ; grep logfile logfile.txt' > locallogfile.txt
cat locallogfile.txt

Resources