导览
- 在 shell 脚本中也可以使用
for
、while
循环 -
until
循环则是和while
循环在条件判断规则上完全相反的的一种循环操作 -
break
命令支持直接终止循环,同时还可以通过break n
指定要终止的循环层级 -
contiune
命令支持直接中止当前循环,直接进入下次循环,同时还可以通过continue n
指定要中止的循环层级 - 在循环结束后可以再最后使用管道干预脚本的输出结果,可以使用重定向将脚本的输出导入文件
13.1 for 命令
- 在 shell 中可以使用
for
命令来循环遍历一系列值,基本语法如下:- 使用效果和其他语法的 for 循环基本一致
for var in list
do
commands
done
13.1.1 读取列表的值
-
for
循环最基本的用法就是读取列表的值,如下图-
name 是在
for
循环中声明的局部变量,但是在循环结束后,该变量依旧可以正常被访问,或者被修改
-
name 是在
[ttxie@41 part13]$ cat for-list.sh
#!/bin/bash
for name in ffjff fffoksfl kkkk lllll
do
echo "当前的名字是${name}"
done
echo "最后名字是: ${name}"
name="newnames"
echo "当前名字是: ${name}"
image.png
13.1.2 读取列表中的复杂值
- 如果需要被遍历的列表中的值存在一些复杂的组合,例如:单引号、双引号、空格
- 这个时候就需要先对这些特殊符号进行转义,方式有以下两种
- 使用反斜线将单引号转义
- 使用双引号将用到单引号、空格的值进行包裹
- 写一个简单的例子演示一下,如下图
-
需要注意的是,在第一个循环中的列表,连续使用了两个没有被转义的单引号,得到了如下的输出结果,如果这里只使用了一个单引号,例如
imagemacbook's cpu is
,造成的错误将会更严重过,会影响整个 shell 脚本无法正常输出结果
-
13.1.3 从变量读取列表
- 将需要被循环的列表存储到变量中,再通过
for
循环进行遍历输出,会更美观,如下图- 变量不仅可以接受待输出的列表值,还能对列表值进行拼接
- 不过这种表现形式在其他语言中更像是字符串而已,不用介意,这就是 shell 的方式
[ttxie@41 part13]$ cat for-variable.sh
#!/bin/bash
names="asssss 1gkmgk 2jkmk"
names=$names" rys" ##追加字符串
for name in $names
do
echo "name: ${name}"
done
image.png
13.1.4 从命令读取值
- 可以用命令替换来执行任何可能产生输出的命令,然后在
for
循环的in
关键字后使用该命令的输出,如下图- 变量 directory 存储了一个目录,然后再
for
循环中使用$(ls $directory)
输出这个目录的内容
- 变量 directory 存储了一个目录,然后再
[ttxie@41 part13]$ cat for-command.sh
#!/bin/bash
for file in `ls $PWD`
do
echo "当前目录有的文件是: ${file}"
done
#-----------还可以这样写-----------
for file in $(ls $PWD)
do
echo "当前目录有的文件是: ${file}"
done
#------------遍历文件中的字符-----------
for state in `cat for-variable.sh`
do
echo ${state}
done
image.png
13.1.5 更改字段分隔符
-
for
循环之所以能将字符串的空格作为列表元素的分隔符,是因为系统中存在 内部字段分隔符( Internal Field Separator ,IFS ) 的全局环境变量 -
IFS 环境变量定义了 shell 作为字段分隔符的多个具体字符,默认情况下,有以下几种
- 空格
IFS=$'\ '
- 制表符
IFS=$'\t'
- 换行符
IFS=$'\n'
- 空格
-
IFS 环境变量可以在 shell 脚本中进行临时修改,如下图
- 下面这个例子中,将 IFS 的值改为只能识别换行符,所以就能顺利的通过循环把每行的内容输出
[ttxie@41 part13]$ cat for-IFS.sh
#!/bin/bash
IFS=$'\n'
for line in $(cat $PWD/for-variable.sh)
do
echo ${line}
done
image.png
-
如果想要为 IFS 指定多个值,可以直接使用
IFS=$'\n':;"
即可- 这就表示换行符、冒号、分号、双引号都会被识别为字段分隔符
-
修改的IFS的值,只在脚本内适用,不改变全局变量。
有时候在一个大脚本中,有的地方需要修改IFS的值,然后忽略这次的修改,在脚本的其他地方继续沿用IFS默认值,可以这样写:
image.png
13.1.6 用通配符读取目录
- 在使用
for
循环时,就算不通过ls
命令( 在 13.1.4 中有演示 )也能读取目录的内容,使用 文件扩展匹配 即可,如下图- 其实就是在路径最后使用通配符
[ttxie@41 part13]$ cat for-wildcards.sh
#!/bin/bash
dir="/BI/xtt/toolkits/shell/part13/*"
for file in ${dir}
do
if [ -d "$file" ]
then
echo "$file is a dir"
elif [ -f "$file" ]
then
echo "$file is a file"
fi
done
image.png
"$file" 加引号 是为了规避含有空格的文件名
- 在
for
循环中还可以同时指定多个目录,实现对输出结果进行拼接的效果,如下图- 由于输出的内容太多,最后执行的时候通过
| head
命令只显示了头部的几条信息
- 由于输出的内容太多,最后执行的时候通过
[ttxie@41 part13]$ cat for-wildcards_plus.sh
#!/bin/bash
dir1="/BI/xtt/toolkits/shell/part13/*"
dir2="/BI/xtt/toolkits/shell/part12/*"
for file in ${dir1} ${dir2}
do
if [ -d "$file" ]
then
echo "$file is a dir"
elif [ -f "$file" ]
then
echo "$file is a file"
fi
done
image.png
13.2 C 语言风格的 for 命令
13.2.1 C 语言的 for 命令
- 在 shell 中可以使用和 C 语言风格类似的
for
命令,基本语法如下
for (( variable assigment ; condition ; iteration process ))
do
commands
done
for (( a = 1 ; a < 10 ; a++ ))
do
echo "a : $a"
done
- 上述的
for
命令语法在以下几个方面没有遵循 shell 标准- 变量赋值可以有空格
- 在条件中调用变量时,不需要通过美元符号开头
- 迭代过程的算式不需要使用
expr
命令
- 写一个简单的例子演示一下,如下图
[ttxie@41 part13]$ cat for-normal.sh
#!/bin/bash
for (( i=1; i<=10; i++ ))
do
echo $i
done
image.png
13.2.2 使用多个变量
- 在这种风格的
for
循环中,可以在条件中定义多个变量,如下图- 可以看到,在变量定义时,同时指定了变量 a 和 b ,并在最后规定了 a 和 b 的迭代方式
- 但需要注意的是,就算可以定义多个变量,但循环结束的条件只能有一个
[ttxie@41 part13]$ cat for-normal-plus.sh
#!/bin/bash
for (( a=1, b=10; a<=10; a++, b-- ))
do
echo "$a - $b"
done
image.png
13.3 while 命令
13.3.1 while 的基本格式
- 当 condition 返回非零的退出状态码时,循环就会结束,否则循环将一直进行
while [ condition ]
do
commands
done
- 写一个简单的例子演示一下,如下图
- 变量 num 初始值为 1
- 循环结束的条件是 num 小于 10
- 符合循环条件时,num 每次都会在输出后,累加 1 ,累加的方式是在第 12 章中学到的使用双括号赋值
- 最后当 num 输出到 9 时,累加后等于 10 ,则无法再次循环
[ttxie@41 part13]$ cat while.sh
#!/bin/bash
n=1
while [ $n -lt 10 ]
do
echo "n的值:${n}"
(( n = ${n} + 1 ))
done
image.png
13.3.2 使用多个测试命令
-
while
命令可以在条件语句中定义多个test
命令,但只有最后一个命令会被作为 检测循环是否结束 的条件,如下图-
可以看到,在条件中定义了两个测试命令,需要注意的是,每个测试命令都必须独占一行
-
其他内容都和上一个 shell 脚本没有区别,但是在输出时,最后会多输出一个 10 ,这也就是
imagewhile
命令支持多个测试命令的意义所在了
-
13.4 until 命令
-
until
命令的效果和while
命令正好相反,但两者的基本语法一致-
while
命令是当条件返回非零时,就结束 -
until
命令则是当条件返回零时,就结束
-
- 写一个简单的例子演示一下,如下图
-
可以看到,当
until
命令使用了和之前while
命令一致的条件判断时,循环体根本无法进入 -
但当使用了之前
imagewhile
命令相反的条件判断时,循环体就顺利进入了
-
13.5 嵌套循环
-
嵌套循环( Nested Loop ) 其实就是多个
for
、while
、until
命令嵌套在一起- 被嵌套的叫 内部循环( Inner Loop )
-
写一个简单的例子演示一下,如下图
image
13.6 循环处理文件数据
- 这个内容其实在上文中的 13.1.5 更改字段分隔符 小节中就有演示
- 这里写一个稍微复杂一点的升级版演示一下,如下图
-
在读取文件之前,将 IFS 的值改为了只识别换行符
-
在循环中输出每行的内容后,又将 IFS 的值改为只识别空格
-
这个时候将每行的数据再次循环,就可以得到每行的具体字符
image
-
13.7 控制循环
13.7.1 break 命令
- 在循环中使用
break
命令可以直接退出循环,在for
、while
、until
中都可以使用
13.7.1.1 退出单个循环
- 可以看到,按照正常的循环逻辑,循环体应该可以执行 10 次,但是由于添加了当值等于 5 时就执行
break
命令的条件判断,所以在值等于 5 时,循环就停止了
[ttxie@41 part13]$ cat for-break.sh
#!/bin/bash
for (( n=1; n<=10; n++ ))
do
echo "n的值为:$n"
if [ $n -eq 5 ]
then
break
fi
done
image.png
13.7.1.2 退出内部循环
-
可以看到,本来外部循环可以执行 5 次,并且在值小于 3 时,每次外部循环执行时,内部循环都可以执行
-
但在第一次外部循环中,内部循环执行两次后,就由于条件判断被中断了
image
13.7.1.3 从内部循环直接退出外部循环
-
break
命令支持使用break n
指定循环的层级,表示会直接退出 n 层的循环体,如下图-
可以看到,shell 脚本的内容和上一个例子基本一致,唯一的修改就是内不循环的
break
改成了break 2
-
在执行脚本后,之前内部循环触发
imagebreak
后,这次造成的结果是整个 shell 脚本的终止
-
13.7.2 continue 命令
-
在循环中使用
continue
命令可以直接中止当前循环,直接进入下一次循环,在for
、while
、until
中都可以使用 -
但是在
while
和until
中使用continue
时需要注意,不能把continue
放在迭代条件之前,否则就会造成无限循环,如下图-
原本
while
循环的条件判断是当 num 小于 5 时,就一直循环,每次循环 num 都会加 1 ,所以一共会循环 5 次 -
但是在 num 的累加操作
(( num = $num + 1 ))
之前增加了一个当num = 2
时就continue
的操作 -
这就导致当 num 等于 2 时,当前循环就会被中止,直接进入下一次循环,而 num 的累加操作每次都没有被执行
-
最后就无限循环了
image
-
-
continue
和break
一样,也可以通过指定层级来跳过对应的层级的循环,如下图-
本来外部循环会循环 5 次,并且每次外部循环时,内部循环都会循环 5 次
-
但是由于
imagecontinue 2
的加入,当内部循环的值等于 2 时,外部循环也会被跳过
-
13.8 处理循环的输出
- 在循环的
done
关键字之后可以使用管道或者重定向操作 - 结合管道的操作在 13.7.2 continue 命令 中已经有演示,效果就是可以对脚本的输出进行干预
- 不过这个演示中是将管道放在了脚本执行时
- 也可以将管道放在脚本内部,
done
关键字之后
- 结合重定向的操作则是可以将脚本的输出重定向到文件中,如下图
-
在循环结束后通过
> result
将输出结果重定向到 result 文件中 -
可以看到,脚本执行后终端没有输出任何语句
-
查看当前目录可以看到出现了一个 result 的文件,里面的内容就是刚才执行脚本的输出内容
image
-
13.9 实例
13.9.1 查找可执行的文件
扫描PATH环境变量中可执行的文件:
[ttxie@41 part13]$ cat find-read.sh
#!/bin/bash
IFS=:
for folder in $PATH
do
echo "folder: $folder"
for file in $folder/*
do
if [ -x $file ]
then
echo " $file"
fi
done
done
image.png
部分内容转载来自:
作者:asing1elife
链接:https://www.jianshu.com/p/b1522b99711a
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
网友评论