linux shell 中 for 和 while 遇到的问题

案例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循环就读不到数据了,因此循环就退出了。

解决办法
  1. 对ssh的stdin进行重定向,在使用管道的时候特别有效
while read ip ; do ssh $ip "uptime" < /dev/null; done < running_hosts
  1. 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

你可能感兴趣的:(linux shell 中 for 和 while 遇到的问题)