Shell for循环用法详解(附带实例)
for 循环是固定循环,也就是在循环时已经知道需要进行几次循环。有时也把 for 循环称为计数循环。
for 循环的语法有两种,接下来分别做详细讲解。
也就是说,假设 in 后面有三个值,for 就会循环三次,第一次循环会把值 1 赋予变量,第二次循环会把值 2 赋予变量,以此类推,如下图所示:

图 1 带列表的for循环
举个简单的例子:
脚本执行之后,结果如下:
上一个例子非常简单,但是没有什么实际应用价值,下面来写一个批量解压缩脚本。
如果我们有很多压缩文件,那么手工逐一解压缩是非常烦琐的,此时可以通过脚本来实现所有文件的解压缩。假设我们把所有的压缩包复制到 /lamp/ 目录中,那么批量解压缩脚本就应该这样写:
在第二种语法中,可以通过指定初始值、循环控制条件、变量变化来确定循环执行次数,如下图所示:

图 2 类C的for循环
在第二种语法中需要注意以下几点:
举一个简单的例子,具体如下:

图 3 循环五次实例
解释一下脚本思路:
1) 类 C 的 for 循环先执行步骤 ①,使用初始值和控制条件做对比,判断是否执行成立。如果不成立,就不执行 do 和 done 之间语句;如果成立,就执行 do 和 done 之间的 echo 语句(步骤 ②)。
2) 在执行完 do 和 done 之间的语句后,执行变量变化,也就是 i=i+1,(步骤 ③)。在执行完变量变化之后,使用经过变化的 i 和控制条件做比较(步骤 ④)。如果判断成立,就执行 do 和 done 之间的语句(步骤 ⑤);如果不成立,就退出 for 循环。
3) 由于步骤 ① 和步骤 ② 只在第一次循环时使用,因此使用虚线来表示。
再看一个实例:
不过,上面的例子仍然和实际工作相距甚远,我们利用 for 固定循环来写一个批量添加用户的脚本。如果需要使用脚本批量添加普通用户,那么这些用户的用户名一定要遵守同一个规则,并且顺序添加,而且用户的初始密码也是一致的,脚本如下:
1) 脚本执行后,让用户自己来决定添加的用户数量、用户名及用户的初始密码。通过使用 read 命令输出提示信息来引导用户进行用户数量、用户名、用户密码的赋值,并把输入分别赋予 num_1、name_1、pass_1。
2) 接下来,使用 if 语句对用户的输入进行判断。先判断“创建用户数量”是否赋值,赋值字符串是不是纯数字。可以使用“=~”的判断方式,因为在“[[]]”中的“=~”可以进行正则判断,随后我们使用“^[0-9]”表示开头为数字,使用“+”表示数字出现一次或任意多次,使用“$”表示用户输入要以数字为结尾。同时,为了避免在执行脚本时“用户数量”输入为“0”,我们判断在“$num_1”的值为 0 时判断不成立。
3) 接下来对“$name_1”进行判断,判断其是否成功取值。然后对“$pass_1”进行判断,判断其取值是否成功。在多个判断式之间使用“&&”作为连接符号,表示逻辑与。当所有判断都成立后,进行循环创建指定数量用户。假设判断不成立,那么执行 else 后的语句,提示输入错误,退出脚本。
在循环创建用户时,使用类 C 的 for 循环。依靠创建用户数量来对循环次数进行限制,每循环一次,就创建一个用户。每创建一个用户,就为相应的用户设置一次初始密码。
这个脚本的执行结果如下:
for 循环的语法有两种,接下来分别做详细讲解。
带列表的for循环
for 变量 in 值1 值2 值3 ... do 程序 donefor 循环的次数取决于 in 后面值的个数(以空格分隔),有几个值就循环几次,并且每次循环都把值赋予变量。
也就是说,假设 in 后面有三个值,for 就会循环三次,第一次循环会把值 1 赋予变量,第二次循环会把值 2 赋予变量,以此类推,如下图所示:

图 1 带列表的for循环
举个简单的例子:
[root@localhost ~]# vim /root/for.sh #!/bin/bash for time in morning noon afternoon evening do echo "This time is $time!" done解释一下脚本思路:因为 in 值后面有四个字符串,并且这些字符串外侧并未使用双引号将其表示为整体,所以 for 会循环四次。每次循环会依次把字符串赋予变量 time,因此这个脚本会循环四次,并依次输出 morning、noon、afternoon、evening 全部四个字符串。
脚本执行之后,结果如下:
[root@localhost ~]# /root/for.sh This time is morning! This time is noon! This time is afternoon! This time is evening!
上一个例子非常简单,但是没有什么实际应用价值,下面来写一个批量解压缩脚本。
如果我们有很多压缩文件,那么手工逐一解压缩是非常烦琐的,此时可以通过脚本来实现所有文件的解压缩。假设我们把所有的压缩包复制到 /lamp/ 目录中,那么批量解压缩脚本就应该这样写:
[root@localhost ~]# /root/auto-tar.sh #!/bin/bash # 批量解压缩脚本 cd /lamp # 进入压缩包目录 ls /lamp/*.tar.* > ls.log # 把所有文件名包含tar的文件以覆盖的方式写入ls.log临时文件 for i in $(cat ls.log) # 读取ls.log文件的内容,文件中有多少个值,就会循环多少次,每次循环把文件名赋予变量i do tar -zxf $i &>/dev/null # 解压缩,并丢弃所有输出 done rm -rf /lamp/ls.log # 删除临时文件 ls.logfor…in… 循环更加贴近于系统管理,如在批量解压缩这个脚本中,如果是固定循环,就要先数有多少个压缩文件,再决定循环多少次。一旦压缩文件的个数发生变化,整个脚本就都需要修改。而使用 for…in… 的方式,压缩文件的个数可以随意变化,不用修改脚本。另外,如果存在 .zip 格式的压缩文件,那么还可以再进行一次 ls/lamp/*.zi 查询,然后继续执行脚本 for 循环进行解压缩。
带类的for循环
for ((初始值; 循环控制条件; 变量变化)) do 程序 donefor 循环的次数可以在循环开始前指定,因此,通常在执行未知次数循环时使用第一种语法,如果已知需要循环的次数就使用第二种语法。
在第二种语法中,可以通过指定初始值、循环控制条件、变量变化来确定循环执行次数,如下图所示:

图 2 类C的for循环
在第二种语法中需要注意以下几点:
- 初始值:在循环开始时,需要给初始值进行赋值,通常变量名为 i,如 i=1;
- 循环控制条件:用于指定变量循环的次数,如 i<=100,则只要变量i的值小于等于 100,循环就会继续;
- 变量变化:每次循环之后变量该如何变化,如 i=i+1,代表每次循环之后,变量 i 的值都加 1。
举一个简单的例子,具体如下:
#!/bin/bash for ((i=1; i<=5; i=i+1)) do echo "$i" done这是一个循环五次的示例,如下图所示:

图 3 循环五次实例
解释一下脚本思路:
1) 类 C 的 for 循环先执行步骤 ①,使用初始值和控制条件做对比,判断是否执行成立。如果不成立,就不执行 do 和 done 之间语句;如果成立,就执行 do 和 done 之间的 echo 语句(步骤 ②)。
2) 在执行完 do 和 done 之间的语句后,执行变量变化,也就是 i=i+1,(步骤 ③)。在执行完变量变化之后,使用经过变化的 i 和控制条件做比较(步骤 ④)。如果判断成立,就执行 do 和 done 之间的语句(步骤 ⑤);如果不成立,就退出 for 循环。
3) 由于步骤 ① 和步骤 ② 只在第一次循环时使用,因此使用虚线来表示。
再看一个实例:
#!/bin/bash # 从1加到100 s=0 for ((i=1; i<=100; i=i+1)) # 定义循环100次 do s=$(($s+$i)) # 每次循环都给变量s赋值 done echo "The sum of 1+2+...+100 is : $s" # 输出从1加到100的和解释一下脚本思路:在这个例子中,请注意“(())”是 Bash 的数字运算格式,必须这样写,才能进行数值运算。
不过,上面的例子仍然和实际工作相距甚远,我们利用 for 固定循环来写一个批量添加用户的脚本。如果需要使用脚本批量添加普通用户,那么这些用户的用户名一定要遵守同一个规则,并且顺序添加,而且用户的初始密码也是一致的,脚本如下:
[root@localhost ~]# vim /root/useradd.sh #!/bin/bash # 批量添加指定数量的用户 read -t 30 -p "请输入要创建用户数量:" num1 # 通过read语句接收创建用户数量 read -t 30 -p "请输入要创建用户名:" name1 # 通过read语句接收创建用户名 read -t 30 -s -p "请输入要创建用户的默认密码:" pass1 && echo "" # 通过read语句接收创建用户默认密码 # 在使用了-s隐藏用户输入后,通常存在不能正确换行的问题。利用echo默认换行的特点为其换行 if [[ $num1 =~ ^[0-9]+$ && $num1 != 0 && -n $name1 && -n $pass1 ]] # 使用[[分别对用户数量、用户名、用户密码进行判断 then echo "各参数取值正常,准备创建用户" for ((i=1; i<=$num1; i=i+1)) # 使用类C的for循环,循环次数通过变量$num1来确定 do useradd ${name1}$i # 用户名称为“名称”+“数字编号”的组合 echo "$pass1" | passwd --stdin ${name1}$i &> /dev/null # 在创建用户结束后,将用户输入的默认密码以非交互的方式为新用户设置密码 done else echo -e "\e[1;31m存在异常参数,请正确输入用户数量、用户名\e[0m" # 经过if判断,如果不成立,就说明用户输入的用户数量、用户名或用户密码存在问题,不创建用户 fi解释一下脚本思路:
1) 脚本执行后,让用户自己来决定添加的用户数量、用户名及用户的初始密码。通过使用 read 命令输出提示信息来引导用户进行用户数量、用户名、用户密码的赋值,并把输入分别赋予 num_1、name_1、pass_1。
2) 接下来,使用 if 语句对用户的输入进行判断。先判断“创建用户数量”是否赋值,赋值字符串是不是纯数字。可以使用“=~”的判断方式,因为在“[[]]”中的“=~”可以进行正则判断,随后我们使用“^[0-9]”表示开头为数字,使用“+”表示数字出现一次或任意多次,使用“$”表示用户输入要以数字为结尾。同时,为了避免在执行脚本时“用户数量”输入为“0”,我们判断在“$num_1”的值为 0 时判断不成立。
3) 接下来对“$name_1”进行判断,判断其是否成功取值。然后对“$pass_1”进行判断,判断其取值是否成功。在多个判断式之间使用“&&”作为连接符号,表示逻辑与。当所有判断都成立后,进行循环创建指定数量用户。假设判断不成立,那么执行 else 后的语句,提示输入错误,退出脚本。
在循环创建用户时,使用类 C 的 for 循环。依靠创建用户数量来对循环次数进行限制,每循环一次,就创建一个用户。每创建一个用户,就为相应的用户设置一次初始密码。
这个脚本的执行结果如下:
[root@localhost ~]# chmod +x /root/useradd.sh # 赋予执行权限 [root@localhost ~]# /root/useradd.sh 请输入要创建用户数量:100 请输入要创建用户名:ls 请输入要创建用户的默认密码: 各参数取值正常,准备创建用户 [root@localhost ~]# tail -n 100 /etc/shadow # 查看用户密码文件,ls1~ls100共100个用户添加完成,默认拥有密码 ls1:$6$sxYINs1/1BpdnXkBSp7HNU1m8A06ZXEgb8vhDdoi/MCGwN5zeXwYERIjEeVOS5mBKSCgzDOPs0LNul2vqm6rlb9/clq0LDoXneOT.1.:19794:0:99999:7.:: ls2:$6$oGfN7.1YB6j6WSa1Srts WmcEm10v6Bq2.98r/CjBfahtEARKpZriWUfg/oaxCXIpREZilB3LBUVHiCUeO32osZxLu/57LGvZDPx9ql/:19794:0:99999:7: ls3:$6$bOzbOPZxouyZkafNSAd706kNMEzq/8gCIMrvwM6nZOjCmgt7GtmtutCEBUoUmt.YCQt2ns9qePmNgtyrg2fSQ22snX4WtpN7LwhR5X.:19794:0:99999:7.:: ...(省略部分命令执行结果)