This question already has answers here:
Execute a command on remote hosts via ssh from inside a bash script
(4 answers)
Closed 7 years ago.
I need a help with a bash script that connect to server as root, execute some commands and then exit from the server.
I tried this script but when login login to server performed the command not running !
#!/bin/bash
sudo ssh -o ConnectTimeout=10 $1 'exit'
if [ $? != 0 ]; then
echo "Could not connect to $1 , script stopped"
exit
fi
sudo ssh $1
echo "SRV=`cat /etc/puppet/puppet.conf | grep -i srv_domain | awk '{print $3}'`"
echo $SRV
echo "puppetMaster=`host -t srv _x-puppet._tcp.$SRV | head -1 | awk '{print $8}' | cut -f1 -d"."`"
echo $puppetMaster
'exit'
I'm surprised nobody has suggested a heredoc yet.
sudo ssh "$1" <<'EOF'
SRV=`cat /etc/puppet/puppet.conf | grep -i srv_domain | awk '{print $3}'`
echo $SRV
echo "puppetMaster=`host -t srv _x-puppet._tcp.$SRV | head -1 | awk '{print $8}' | cut -f1 -d"."`"
echo $puppetMaster
EOF
This feeds everything from the <<'EOF' until the line starting with EOF into the stdin of ssh, to be received and run by the remote shell.
The commands following ssh machine in a script are not run on the machine. They will be run on the local machine once the ssh exits.
Either specify the commands to run as an argument of ssh, or alternatively, run ssh and make it read the commands from standard input, and send the commands to it.
ssh machine ls
# or
echo ls | ssh machine
You seem to be a little confused as to what runs where.
ssh -o ConnectTimeout=10 $1 'exit'
will connect to $1, run exit, and disconnect.
ssh -o ConnectTimeout=10 $1 'echo hello world'
will print hello world on
the server and then disconnect.
ssh $1
will open up a shell on the remote. After the shell has ended, the following commands will run locally.
echo "SRV=`cat /etc/puppet/puppet.conf | grep -i srv_domain | awk '{print $3}'`"
echo $SRV
echo "puppetMaster=`host -t srv _x-puppet._tcp.$SRV | head -1 | awk '{print $8}' | cut -f1 -d"."`"
echo $puppetMaster
'exit'
What you probably want is start bash on the remote and forward to it the commands you want to give it via stdin.
echo "my commands" | ssh $1 bash
Technically, you don't need that bash -- ssh will start bash even without it (but with different rc files).
Related
Hope this time it's not a duplicate. I didn't find anything.
My code:
#!/bin/bash
FILE=/home/user/srv.txt
TICKET=task
while read LINE; do
ssh -nT $LINE << 'EOF'
touch info.txt
hostname >> info.txt
ifconfig | grep inet | awk '$3 ~ "cast" {print $2}' >> info.txt
grep -i ^server /etc/zabbix/zabbix_agentd.conf >> info.txt
echo "- Done -" >> info.txt
EOF
ssh -nT $LINE "cat info.txt" >> $TICKET.txt
done < $FILE #End
My issue:
if I only use ssh $LINE it will only ssh to the host on the first line and also display an error Pseudo-terminal will not be allocated because stdin is not a terminal.
using ssh -T , fix the error message above and it will create the file info.txt
using ssh -nT , fix the error where ssh only read the first line but I get an error message cat: info.txt: No such file or directory. If I ssh to the hosts, I can confirm that there is no info.txt file in my home folder. and with ssh -T, I have this file in my home folder.
I tried with the option -t, also HERE, EOF without ' ... ' but no luck
Do I miss something?
Thanks for your help,
Iswaren
You have two problems.
If you invoke ssh without -n it may consume the $FILE input (it drains its stdin)
If you invoke ssh with -n it won't read its stdin, so none of the commands will be executed
However, the first ssh has had its input redirected to come from a heredoc, so it does not need -n.
As stated in the comments, the second ssh call is not needed. Rather than piping into info.txt and then copying that into a local file, just output to the local file directly:
while read LINE; do
ssh -T $LINE >>$TICKET.txt <<'EOF'
hostname
ifconfig | grep inet | awk '$3 ~ "cast" {print $2}'
grep -i ^server /etc/zabbix/zabbix_agentd.conf
echo "- Done -"
EOF
done <$FILE
I'm trying to use the script below to extract values from the df command on remote servers, then record to a log file. SSH keys are in place and no password is needed (this is not the problem).
It's getting hung up, however, and not spitting back output.
#!/bin/bash
PATH=/bin:/usr/bin:/usr/sbin
export PATH
SERVERLIST=/opt/scripts/server-list.dat
while IFS='|' read -u 3 hostname; do
echo evaluating $hostname...
SIZE=$(ssh $hostname | df -Pkhl | grep '/Volumes/UserStorage$' | awk '{print $2}')
echo $SIZE
done 3< $SERVERLIST
exit 0
You need to run df on the remote system, not pipe the output of an interactive ssh to it:
SIZE=$(ssh -n $hostname df -Pkhl | grep '/Volumes/UserStorage$' | awk '{print $2}')
Also, use the -n option to ssh to keep it from trying to read from stdin, which would consume the rest of the lines from the server list file.
This question already has answers here:
ssh breaks out of while-loop in bash [duplicate]
(2 answers)
Closed 7 years ago.
In the below code, while loop is executing only one time whereas there are entry in crawler.cfg file.
when I am commmenting VAR=$(ssh ${HOSTS} ps ax | grep -v grep | grep $SERVICE|wc -l) line in code then it is looping three times and working fine...
So, What is problem in this line?
Please assist.
while read crawler_info
do
PATH_OF_SERVER="/home/Crawler/"
THREAD_SCRIPT=crawler18.sh
HOSTS=$(echo $crawler_info|cut -d'|' -f1)
SERVICE="java"
VAR=$(ssh ${HOSTS} ps ax | grep -v grep | grep $SERVICE|wc -l)
if [ $VAR -ne 0 ]
then
echo "$SERVICE service running, everything is fine on ${HOSTS} node"
else
echo "java services is not running on ${HOSTS} node. process is triggering java services"
ssh ${HOSTS} ${PATH_OF_SERVER}${THREAD_SCRIPT} > /dev/null 2> /dev/null&
if [ $? -eq 0 ]
then
echo "java services triggered successfully on ${HOSTS} node"
else
echo "process is unable to trigger the java services on ${HOSTS} node"
fi
fi
done < crawler.cfg
crawler.cfg
n0007
n00011
n0000023
This is rather a FAQ.
The easiest way to solve it is to use a FD other than 0:
while read -u 3 ...
done 3<crawler.cfg
Alternately, redirect ssh's stdin from /dev/null in both invocations:
VAR=$(ssh ${HOSTS} ps ax </dev/null | grep -v grep | grep $SERVICE|wc -l)
ssh ${HOSTS} ${PATH_OF_SERVER}${THREAD_SCRIPT} </dev/null >/dev/null 2>&1
This script reads the system IP from hosts.txt, login to system, checks the OS type, executes a set of commands and print the output.
The ssh portion works fine, however the error (No such File or Directory) is shown after displaying output for 'ls''.
It seems the command /opt/hyperic/agent-current/bin/hq-agent.sh is not getting executed on remote host. The intend is to execute commands 'cd /opt;ls and also capture the command output to STATUS on each remote systems mentioned in host.txt.
When I run manaully the command on the remote system, the below output is returned. Any help on what could be wrong here?
~]# /opt/hyperic/agent-current/bin/hq-agent.sh status | awk 'NR==1{print $3 $4}'
isrunning
script is as below
#!/bin/bash
while read host; do
if ssh -o StrictHostKeyChecking=no -n root#$host '[ "$(awk "/CentOS/{print}" /etc/*release)" ] '
then
echo "(centos)"
ssh -o StrictHostKeyChecking=no -n root#$host 'cd /opt;ls'
STATUS=`/opt/hyperic/agent-current/bin/hq-agent.sh status | awk 'NR==1{print $3 $4}'`
if [ "$STATUS" == "isrunning" ]
then
echo "$HOST == PASS"
else
echo "$HOST == FAIL"
fi
else
echo "(generic)"
fi
done < hosts.txt
Output of the script --
root#10.10.1.1's password:
firstboot
puppet
./hq-enhanced.sh: line 14: /opt/hyperic/agent-current/bin/hq-agent.sh: No such file or directory
== FAIL
Ahh... I see what is happening:
Key to the question is:
ssh -o StrictHostKeyChecking=no -n root#$host 'cd /opt;ls'
STATUS=`/opt/hyperic/agent-current/bin/hq-agent.sh status | awk 'NR==1{print $3 $4}'`
the ssh command runs immediately and returns control to the script - at this point your not logged in via ssh anymore and the line starting STATUS executes wherever your running your script from.
To capture the output of the ssh command you would need something like:
STATUS=`ssh root#foobar -c 'cd /foo/bar && /opt/hyperic/agent-current/bin/hq-agent.sh ...'`
HTH
I wrote a script to ssh to remote server to find the disk usage of a user. However, this script can only read the first line, it doesn't continue on the other lines of the file. Anything wrong with my script? Thanks.
#!/bin/bash
FILE="myfile.txt"
while read line; do
server=`echo $line|awk '{print $1}'`
cpid=`echo $line|awk '{print $2}'`
echo $server "---" $cpid "---" `ssh $server grep $cpid /var/cpanel/repquota.cache|awk '{print int($3/1000) "MB"}'`
done < $FILE
myfile.txt contents:
server1 user1
server2 user2
server3 user3
The ssh call is inheriting its standard input from the while loop, which redirects from your file. This causes the ssh command to consume the rest of the file. You'll need to use a different file descriptor to supply the read command:
#!/bin/bash
FILE="myfile.txt"
while read -u 3 server cpid; do
printf "$server---$cpid---"
ssh $server "grep $cpid /var/cpanel/repquota.cache | awk '{print int($3/1000) \"MB\"}'"
done 3< $FILE
An alternative is to explicitly redirect input to ssh from /dev/null, since you're not using it anyway.
#!/bin/bash
FILE="myfile.txt"
while read server cpid; do
printf "$server---$cpid---"
< /dev/null ssh $server "grep $cpid /var/cpanel/repquota.cache | awk '{print int($3/1000) \"MB\"}'"
done < $FILE
First of all you can simplify your read loop to
while read server cpid; do
echo $server "---" $cpid "---" `ssh ...`
done <$FILE
and save the parsing with awk. Another simplification is to save the call to grep and let awk do the search for $cpid
ssh $server "awk '/$cpid/ {print int(\$3/1000) \"MB\"}' /var/cpanel/repquota.cache"
To your problem, I guess the ssh call doesn't return, because it waits for a password or something, and so prevents the loop to continue.