我想要一个bash脚本,能够执行以下操作:
for c in computers:
do
ping $c
if ping is sucessfull:
ssh $c 'check something'
done
如果我只使用 ssh
命令,而电脑无法响应,超时时间会非常长。因此,我想使用 ping
命令的输出来确定计算机是否存活。如何做到这一点?其他想法也很好。
使用 ping
的返回值:
for C in computers; do
ping -q -c 1 $C && ssh $C 'check something'
done
ping
如果单个 ping (-c 1
) 成功,则以值 0 退出。在 ping 超时或者 $C
无法解析的情况下,它将以非零值退出。
在ping
命令中使用-w
开关(或在FreeBSD和OS X上使用-t
),然后检查命令的返回值。
ping -w 1 $c
RETVAL=$?
if [ $RETVAL -eq 0 ]; then
ssh $c 'check something'
fi
-w
传递的参数,如果你要连接的主机距离较远且延迟较高。man ping
中得知: -w deadline
Specify a timeout, in seconds, before ping exits regardless of
how many packets have been sent or received. In this case ping
does not stop after count packet are sent, it waits either for
deadline expire or until count probes are answered or for some
error notification from network.
并非所有的网络环境都允许ping命令(虽然很多可以),也不是所有的主机都会回应ping请求。我建议不要使用ping,而是设置ssh连接超时时间:
for c in computers; do ssh -o ConnectTimeout=2 $c '检查某些东西' done
我在1997年编写了这样的脚本,并在接下来的几年中大量使用它:sshall。
它很简单,不太灵活。另一方面,它支持一些您可能不需要的检查。
一旦我开始以更多样化的方式使用ssh
,我就停止使用或更新此脚本;现在我要么直接编写shell循环,要么使用Ansible adhoc commands。
这个脚本:
#!/bin/sh
#
# $Id: sshall 1259 2017-06-26 16:59:42Z rp $
# sshall: ssh to multiple hosts, *last* arg is command
# with -i, also accepts input ... I'd rather dup stdin or so, but how?
PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/usr/etc; export PATH
tmpfile=/tmp/sshall-$$
# error handling
trap 'rm -f $tmpfile; exit' 1 2 3 4 13 15
#--- cmdline parsing ---#
#
Puke()
{
if [ -n "$*" ]; then echo Fatal error: $* 1>&2; fi
cat <<ZZ 1>&2
Usage:
$0 [-v] [-i] [-e] [-b] [-u user] [-H] [-Y] [-P] host1 [host2 [...]] "command"
to issue "ssh host command" for every host
use -i flag to supply input, -e to redirect stderr to stdout,
-v for progress messages, -b to start in the background,
-u user to connect as the given user,
-H to check the hostnames with 'host',
-Y to check them with 'ypmatch',
-P to check them with 'ping',
-o text to pass the given option through to ssh
note: the effect of -i is to call ssh without the -n flag
take care: -b may fill up your process table if used on many hosts
ZZ
exit 1
}
input=
hostlist=
verbose=
bg=
check_w_host=
check_w_ypmatch=
check_w_ping=
user_prefix=
while :
do
case "$1" in
-h|-help|\?*) Puke;;
-b) bg=1
if [ -n "$command" ]; then Puke "options must precede arguments"; fi;;
-i) input=1
if [ -n "$command" ]; then Puke "options must precede arguments"; fi;;
-v) verbose=1
if [ -n "$command" ]; then Puke "options must precede arguments"; fi;;
-e) errtoout=1
if [ -n "$command" ]; then Puke "options must precede arguments"; fi;;
-o)
if [ -n "$o_opt" ]; then Puke "specify only one -o option"; fi
shift; o_opt="$1"
if [ -n "$command" ]; then Puke "options must precede arguments"; fi;;
-u) shift; user_prefix="$1@"
if [ -n "$command" ]; then Puke "options must precede arguments"; fi;;
-H) check_w_host=1
if [ -n "$command" ]; then Puke "options must precede arguments"; fi;;
-Y) check_w_ypmatch=1
if [ -n "$command" ]; then Puke "options must precede arguments"; fi;;
-P) check_w_ping=1
if [ -n "$command" ]; then Puke "options must precede arguments"; fi;;
-*) Puke "$1 is not a valid option" ;;
"") break;;
*) hostlist="$hostlist $command"; command=$1;;
esac
shift
done
if [ -z "$command" ]
then
Puke "no command supplied"
fi
if [ -z "$hostlist" ]
then
Puke "no host(s) supplied"
fi
case "$user_prefix" in
-*)
Puke "no -u argument supplied" ;;
esac
if [ -n "$check_w_host" ]
then
for h in $hostlist
do
if host 2>&1 >/dev/null
then
Puke "host cannot find '$h'"
fi
done
fi
if [ -n "$check_w_ypmatch" ]
then
for h in $hostlist
do
if ypmatch hosts 2>&1 >/dev/null
then
Puke "ypmatch cannot find '$h'"
fi
done
fi
#-- OK, start doing useful things ---#
#
if [ -n "$input" ]
then
# read input!
cat >$tmpfile
# we can do away with the $tmpfile, with a fork for every host ...
fi
Ssh()
{
case "$errtoout" in
"") ssh "$@" | sed "s/^/$h: /" ;;
*) ssh "$@" 2>&1 | sed "s/^/$h: /" ;;
esac
}
Ssh_o()
{
case "$o_opt" in
"") Ssh "$@";;
*) Ssh -o "$o_opt" "$@";;
esac
}
Ssh_w_tmp()
{
if [ -f "$tmpfile" ]
then
cat $tmpfile | Ssh_o "$@"
else
Ssh_o -n "$@"
fi
}
for h in $hostlist
do
if [ -z "$check_w_ping" ] || ping $h 2 >/dev/null # note: "2 >"
# host is active
then
#if [ -z "`finger @$h 2>&1 | grep 'Connection refused$'`" ]
# host accepts finger - very crude check to see if ssh will work
# however, finger has been disabled since, where I live
if true
then
if [ -n "$verbose" ]
then
echo "executing '$command' on '$h'" 1>&2
fi
case "$bg" in
"")
Ssh_w_tmp $user_prefix$h "$command" ;;
*)
Ssh_w_tmp $user_prefix$h "$command" & ;;
esac
fi
fi
done
rm -f $tmpfile
这是我的技巧:
#ipaddress shell variable can be provided as an argument to the script.
while true
do
nmap_output=$(nmap -p22 ${ipaddress})
$(echo ${nmap_output} | grep -q open)
grep_output=$?
if [ "$grep_output" == 0 ] ; then
#Device is LIVE and has SSH port open for clients to connect
break
else
#[01 : bold
#31m : red color
#0m : undo text formatting
echo -en "Device is \e[01;31mdead\e[0m right now .... !\r"
fi
done
#\033[K : clear the text for the new line
#32 : green color
echo -e "\033[KDevice is \e[01;32mlive\e[0m !"
ssh user@${ipaddress}
不仅依赖于ping
。为什么?
- 成功的ping
并不能保证您成功访问ssh
。您仍然可以在此脚本的开头添加ping
测试,如果ping失败,则退出并从上面不执行任何操作。
上述bash
脚本片段验证您尝试访问的设备是否为客户端(您)打开了SSH端口。需要安装nmap
软件包。
我不明白为什么您要在该脚本中ssh
到多台计算机。但是,我的脚本适用于ssh到一个设备,并可根据您的需求进行修改。
使用64作为测量工具是不合逻辑的。最好使用接收/丢失数据包的数量。
这个脚本可以工作:
RESULT="1"
PING=$(ping ADDRESS -c 1 | grep -E -o '[0-9]+ received' | cut -f1 -d' ')
if [ "$RESULT" != "$PING" ]
then
DO SOMETHING
else
DO SOMETHING
fi
ping -q -c 1 bogus.local; and echo "pinging the host worked"; or echo "pinging the host didn't work"
while true;
do
RESULT="1"
PING=$(ping 8.8.8.8 -c 1 | grep -E -o '[0-9]+ received' | cut -f1 -d' ')
if [ "$RESULT" != "$PING" ]
then
echo "FAIL"
exit 0
else
echo "connection is okay.."
fi
done
RESULT="64"
PING=$(ping 127.0.0.1 -c 1 | grep 64 | awk '{print $1}')
if [ "$RESULT" != "$PING" ]
then
#ping failed
else
#ping successful, do ssh here
fi
man ping
,倾向于认为这种行为是ping
中的一个 bug,因为在这种情况下我期望返回值是 2。引用一下文档中的内容:"如果 ping 没有接收到任何响应数据包,它将以代码1退出。如果指定了数据包计数和截止时间,并且在截止时间到达之前接收到少于计数数据包,则它也将以代码1退出。在其他错误时,它会以代码2退出。否则它以代码0退出,这使得使用退出代码来查看主机是否处于活动状态成为可能。" 你对此有什么看法? - Stephan202