案例1: while 循环体中有ssh 时,只执行一次就退出了
假设 ips 里的内容如下
192.168.0.3
192.168.0.4
192.168.0.5
192.168.0.6
...
执行ssh脚本检查这些机器的运行时间
while read ip ; do ssh $ip "uptime"; done < ips
# 10:45:29 up 969 days, 12:44, 0 users, load average: 2.43, 3.59, 3.35
# 后面没有了
而使用for时
for ip in $(cat running_hosts ) ; do ssh $ip "uptime" ; done
# 10:43:07 up 969 days, 12:41, 0 users, load average: 3.43, 3.96, 3.39
# 10:43:07 up 965 days, 20:41, 0 users, load average: 4.04, 3.73, 3.89
# 10:43:08 up 885 days, 16:41, 0 users, load average: 1.70, 1.42, 1.47
# 10:43:09 up 882 days, 15:41, 0 users, load average: 1.49, 1.56, 1.62
# ...
为什么会这样呢?
原因:ssh会从stdin中读取数据,在第一次执行的时候就把stdin中的剩余行都读完了; 然后while循环就读不到数据了,因此循环就退出了。
解决办法
- 对ssh的stdin进行重定向,在使用管道的时候特别有效
while read ip ; do ssh $ip "uptime" < /dev/null; done < running_hosts
- while不使用stdin,例如使用fd编号为3的管道,或者其他fd
while read ip <&3 ; do ssh $ip "uptime"; done 3< running_hosts
案例2: 作用域
# temp.txt 里面有100行
i=0
cat temp.txt | while read line
do
i=$(($i + 1))
done
echo $i # 0,原因是通过管道符,shell帮我启动了一个新的进程,子进程修改的是自己的局部变量,在主进程中不受影响
j=0
while read line
do
j=$(($j + 1))
done < temp.txt
echo $j # 100
k=0
for t in $(cat temp.txt)
do
k=$(($k + 1))
done
echo $k # 100
网友评论