在shell编程中经常用到循环,常用的循环有for和while循环两种。while循环默认以行读取文件,而for循环以空格读取文件切分文件,本篇就结合现网的一些使用示例说说二者的用法和区别。

一、常用语法

1、for循环

for循环常用的语法结构有如下几种:

1for 变量 in seq字符串
2for 变量 in `command`  " "
3for 变量 in "$@"或“$*4for((赋值;条件;运算语句))

2、while循环

while循环常用的语法结构有如下几种:

1while [ $i -lt num ]
2while true
3while read a b c; do command done < filename
4cat filename | while read a b c

二、行读取示例

这里以常见的df获取磁盘信息为例,了解下使用for和while的几种循环方法处理时的区别。先看下我写的脚本,内容如下:

 1#/bin/bash
 2## author: yangbk
 3## site: www.361way.com
 4## mail: itybku@139.com
 5## desc: test loop for in and while
 6df -hl|awk 'int($5) >30 ' > testfile
 7result=`df -hl|awk 'int($5) >30 '`
 8echo '******************* for testing *****************'
 9for i in $result;do
10        echo $i
11done
12echo '******************* while echo test *************'
13echo $result | while read line
14do
15    echo $line
16done
17echo '****************** while testing ****************'
18df -hl|awk 'int($5) >30 '|while read line
19do
20    echo $IP `hostname` $line
21done
22echo '****************** while read file **************'
23while read line
24do
25    echo $IP `hostname` $line
26done < testfile

上面的脚本执行时结果如下:

 1# sh forwhile.sh
 2******************* for testing *****************
 3/dev/sda3
 49.5G
 55.7G
 63.4G
 764%
 8/
 9/dev/sda2
1039G
1119G
1218G
1352%
14/home
15/dev/sda6
169.5G
177.1G
182.0G
1978%
20/usr
21******************* while echo test *************
22/dev/sda3 9.5G 5.7G 3.4G 64% / /dev/sda2 39G 19G 18G 52% /home /dev/sda6 9.5G 7.1G 2.0G 78% /usr
23****************** while testing ****************
24localhost /dev/sda3 9.5G 5.7G 3.4G 64% /
25localhost /dev/sda2 39G 19G 18G 52% /home
26localhost /dev/sda6 9.5G 7.1G 2.0G 78% /usr
27****************** while read file **************
28localhost /dev/sda3 9.5G 5.7G 3.4G 64% /
29localhost /dev/sda2 39G 19G 18G 52% /home
30localhost /dev/sda6 9.5G 7.1G 2.0G 78% /usr

可以看到,只有后面两种方法可以正常获取到我们想要的数据,前面两种方法在处理时和我们想要的结果都不一样。此示例得出的结果为:

1、while循环: 以行读取文件,默认分隔符是空格或者Tab;
2、for循环: 以空格读取文件,也就是碰到空格,就开始执行循环体,所以需要以行读取的话,就要把空格转换成其他字符

三、ssh连接与wait

这里还是以一个测试脚本为例:

 1#!/bin/bash
 2## author: yangbk
 3## site: www.361way.com
 4## mail: itybku@139.com
 5## desc: test wait and ssh when use for in and while
 6# while loop
 7echo -en "\t";date
 8cat abc.txt|while read user ip
 9do
10{
11 ssh -o ConnectTimeout=10 $user@$ip "hostname" < /dev/null
12 sleep 10s
13} &
14done
15wait
16echo "This is while loop."
17echo -en "\t";date
18sleep 10s
19echo -e "\n"
20# for loop
21echo -en "\t";date
22for line in `cat abc.txt|sed -e 's/ /--/g'`
23do
24{
25 user=`echo $line|awk -F '--' '{print $1}'`
26 ip=`echo $line|awk -F '--' '{print $2}'`
27 ssh -oConnectTimeout=10 $user@$ip "hostname"
28 sleep 10s
29} &
30done
31wait
32echo "This is for loop."
33echo -en "\t";date

此示例的结果这里不再输出,具体可以使用该脚本ssh几台主机做个测试,测试后得到结果如下:

1、for循环: 循环体在后台执行,等待循环体全部执行结束,后面的命令接着执行。
2、while循环: wait没起到作用,循环体在后台执行,后面的命令也同时在执行。循环体内有ssh、scp、sshpass的时候有执行一次循环就退出的情况,解决该问题方法有如下两种:

  • a、使用ssh -n “command” ;
  • b、将while循环内加入null重定向,如 ssh “cmd” < /dev/null 将ssh 的输入重定向输入。

四、执行效率

在对大文件进行按行读取(for在读取文件时,可以for i in cat filename进行按行读取)的效率方面,经测试while 要更快一些。测试脚本可以去我的github上去取。while重定向读文件的方法还有另一种不常见的方法,有兴趣的可以看下我的另一篇 ---shell下读取文件的方法