我想要一个可以执行以下操作的 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
无法解决时,它将以非零值退出。
使用命令上的-w
开关(或-t
在 FreeBSD 和 OS X 上)ping
,然后检查命令的返回值。
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 命令。
剧本:
#!/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
的脚本片段,验证您尝试访问的设备是否打开了 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