【发布时间】:2010-12-16 05:18:54
【问题描述】:
我想要一个 bash 脚本:
for c in computers:
do
ping $c
if ping is sucessfull:
ssh $c 'check something'
done
如果我只做ssh 并且计算机没有响应,那么超时将永远存在。所以我正在考虑使用ping 的输出来查看计算机是否还活着。我怎么做?其他想法也会很棒
【问题讨论】:
我想要一个 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 (-c 1) 成功,ping 将以值 0 退出。在 ping 超时或无法解析 $C 时,它将以非零值退出。
【讨论】:
man ping,我倾向于认为这种行为是ping 中的一个错误,因为在这种情况下我希望返回值为2。 Quote: "如果 ping 根本没有收到任何回复数据包,它将以代码 1 退出。如果同时指定了数据包计数和截止时间,并且在截止时间到达时收到的数据包少于计数,它将也以代码 1 退出。在其他错误时,它以代码 2 退出。否则以代码 0 退出。这使得可以使用退出代码来查看主机是否处于活动状态。" 您对此有何看法这个?
在ping 命令上使用-w 开关(或-t 在FreeBSD 和OS X 上),然后检查命令的返回值。
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 设置连接超时:
用于计算机中的 c;做 ssh -o ConnectTimeout=2 $c '检查一下' 完毕【讨论】:
我在 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
【讨论】:
使用 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
【讨论】:
这是我的技巧:
#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 test 添加到此脚本的开头,如果 ping 失败则退出并且不执行上述操作。
以上bash脚本sn-p,验证您尝试的设备是否
访问会打开 SSH 端口供客户端(您)连接。需要安装nmap 包。
我不明白您为什么要在该脚本中将ssh 发送到多台计算机。但是,我的适用于 ssh 到一个设备中,并且可以根据您的需要进行修改。
【讨论】:
承认引用 Bash 的原始问题,这里有一个示例供任何希望在 Fish shell 中完成此操作的人使用:
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
【讨论】:
在你的 bash 循环中使用它:
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
【讨论】: