我刚刚编写了以下 bash 脚本来检查 Linux 计算机列表上的 ping 访问:
for M in $list
do
ping -q -c 1 "$M" >/dev/null
if [[ $? -eq 0 ]]
then
echo "($C) $MACHINE CONNECTION OK"
else
echo "($C) $MACHINE CONNECTION FAIL"
fi
let C=$C+1
done
这打印:
(1) linux643 CONNECTION OK
(2) linux72 CONNECTION OK
(3) linux862 CONNECTION OK
(4) linux12 CONNECTION OK
(5) linux88 CONNECTION OK
(6) Unix_machinetru64 CONNECTION OK
如何printf
在 bash 脚本中使用(或任何其他命令)来打印以下格式?
(1) linux643 ............ CONNECTION OK
(2) linux72 ............. CONNECTION OK
(3) linux862 ............ CONNECTION OK
(4) linux12 ............. CONNECTION OK
(5) linux88 ............. CONNECTION FAIL
(6) Unix_machinetru64 ... CONNECTION OK
答案1
使用参数扩展来替换由%-s
点产生的空格:
#!/bin/bash
list=(localhost google.com nowhere)
C=1
for M in "${list[@]}"
do
machine_indented=$(printf '%-20s' "$M")
machine_indented=${machine_indented// /.}
if ping -q -c 1 "$M" &>/dev/null ; then
printf "(%2d) %s CONNECTION OK\n" "$C" "$machine_indented"
else
printf "(%2d) %s CONNECTION FAIL\n" "$C" "$machine_indented"
fi
((C=C+1))
done
答案2
for m in $list
是zsh
语法。就在bash
其中for i in "${list[@]}"
。
bash
没有填充运算符。您可以使用空格进行填充printf
,但只能使用空格,而不能使用任意字符。zsh
有填充运算符。
#! /bin/zsh -
list=(
linux643
linux72
linux862
linux12
linux88
Unix_machinetru64
)
c=0
for machine in $list; do
if ping -q -c 1 $machine >& /dev/null; then
state=OK
else
state=FAIL
fi
printf '%4s %s\n' "($((++c)))" "${(r:25::.:):-$machine } CONNECTION $state"
done
这填充运算符${(r:25:)parameter}
是正确的-pad长度为25,带有空格${(r:25::string:)parameter}
或正确的- 用任何字符串而不是空格填充。
我们也printf '%4s'
用来左边- 用空格填充(x)
。我们本来可以用它来${(l:4:):-"($((++c)))"}
代替。但一个显着的区别是,如果字符串长度超过 4 个字符,${(l)}
则会将其截断,而会溢出printf
.
答案3
格式%s
说明符可以采用精度(%.20s
例如),就像当您想要将浮点值输出到特定精度时(例如%.4f
)一样,输出最多将是给定字符串参数中的多个字符。
因此,创建一个包含机器名称和足够的点以用完点的字符串:
cnt=0
for hname in vboxhost ntp.stupi.se example.com nonexistant; do
if ping -q -c 1 "$hname" >/dev/null 2>&1; then
status="OK"
else
status="FAIL"
fi
printf "(%d) %.20s CONNECTION %s\n" \
"$(( ++cnt ))" "$hname ...................." "$status"
done
输出:
(1) vboxhost ........... CONNECTION OK
(2) ntp.stupi.se ....... CONNECTION OK
(3) example.com ........ CONNECTION OK
(4) nonexistant ........ CONNECTION FAIL
答案4
fping
我会用和来做awk
。不幸的是,awk
'printf
不能用点填充,只能用空格或零填充,所以我必须编写一个函数:
list=(kali surya indra ganesh durga hanuman nonexistent)
fping "${list[@]}" 2>&1 |
sort -k3 |
awk -F'[: ]' 'BEGIN { fmt="(%02d) %s CONNECTION %s\n"};
function dotpad(s,maxlen, l,c,pads) {
l = maxlen - length(s);
pads = "";
for (c=0;c<l;c++) {pads=pads"."};
return s " " pads
};
/alive$/ { printf fmt, ++i, dotpad($1,19), "OK" };
/unreachable$/ { printf fmt, ++i, dotpad($1,19), "FAIL" }
/not known$/ { printf fmt, ++i, dotpad($1,19), "IMPOSSIBLE" } '
(01) durga .............. CONNECTION OK
(02) ganesh ............. CONNECTION OK
(03) indra .............. CONNECTION OK
(04) kali ............... CONNECTION OK
(05) nonexistent ........ CONNECTION IMPOSSIBLE
(06) hanuman ............ CONNECTION FAIL
(07) surya .............. CONNECTION FAIL
我在括号中使用零填充的 2 位数字,这样如果有 10-99 个主机$list
(100+ 仍然会搞砸),格式就不会搞砸。另一种方法是延迟打印直到出现一个END {}
块,并且 /regexp-matches/ 仅将主机名插入到三个数组之一中,例如ok
, fail
, unknown
。或者只是一个关联数组(例如hosts[hostname]="OK"
)。然后,您可以计算行数并使用它来决定行计数器字段的宽度。
我还决定让输出区分未知主机 ( CONNECTION IMPOSSIBLE
) 和无法访问的主机 ( CONNECTION FAIL
)。
是sort -k3
可选的,它只是按结果对输出进行分组fping
(“主机名处于活动状态”、“主机名无法访问”或“主机名:名称或服务未知”)。如果没有sort
,未知主机将始终首先出现在输出中。只是简单地sort
没有-k3
将按主机名排序。