运维入门之bash shell脚本四(结构化命令for、while、util)
for命令:
for var in list
do
commands
done
$user 变量保持了其值,也允许我们修改它的值,并在for命令循环之外跟其他变量一样使用
从命令读取值:
![]()
一个特殊的环境变量IFS,叫做内部字段分隔符( internal field separator ),IFS环境变量定义了bash shell 用作字段分隔符的一系列字符,默认情况下,bash shell 会将 空格 、 制表符、 换行符 当做字段分隔符。当然,可以通过在shell脚本中临时修改IFS环境变量的值来限制被bash shell 当做字段分隔符的字符。
例如:如果你想修改IFS的值,使其只能识别换行符,则 IFS = $ '\n'
在处理代码量较大的脚本时。可能在一个地方需要修改IFS的值,然后忽略这次修改,在脚本其他地方继续沿用IFS默认值,一个可参考的安全实践是在改变IFS之前保存原来的IFS值,之后在恢复它,可以通过
IFS.OLD=$ IFS
IFS=$'\n'
<在代码中使用新的IFS值>
IFS=$IFS.OLD
这就保证了在脚本的后续操作中使用的是默认的IFS值
如果要指定多个IFS字符,只要将它们在赋值行串起来就行了
IFS=$'\n':;"
while命令:
格式为 while test command
do
other cammands
done
while命令允许你在while语句行定义多个测试命令,只有最后一个测试命令的退出状态码会被用来决定什么时候结束循环。
util命令和while命令刚好相反,只有测试命令的退出状态码不为0,bash shell才会执行循环中列出的命令,一点测试命令返回了退出状态码0,循环就结束了(和while一样,同样可以有多个测试命令)
until test commands
other commands
done
循环处理文件:
通常需要遍历文件中的数据,这要求结合已经讲过的两种技术:
1、使用嵌套循环
2、修改IFS环境变量
下面的例子是从/etc/passwd中获取数据,先逐行遍历/etc/passwd文件,并将IFS变量的值改成冒号,从而分割每行数据中的字段
上述脚本使用两个不同的IFS值来解析数据,第一个IFS值解析出/etc/passwd文件中的单独行,内部for循环接着将IFS修改为冒号,允许你从/etc/passwd的行中解析出单独的值。
控制循环:
break、continue
1、跳出单个循环
2、跳出内部循环
当使用了多重循环时,break只会退出你所在的最内层循环。
3、跳出外部循环;
break 命令接受单个命令行参数: break n
continue与break用法一样
如果continue跳过的循环中包含变量的自增问题就会出现
处理循环的输出:
在shell脚本中,你可以对循环的输出使用管道或进行重定向,这可以在done命令之后添加一个处理命令来实现
实例:搜索某个文件夹下的可执行文件
![]()
用通配符读取目录:
可以用for命令来自动遍历目录中的文件。进行此操作时必须在文件名或路径名中使用通配符。它会强制shell使用文件扩展匹配。
#!/bin/bash
#iterate through all the files in a directory
for file in /home/ZHJIAB/test/*
do
if [ -d "$file" ]
then
echo "$file is a directory"
elif [ -f " $file " ]
then
echo "$file is a file "
fi
done
如果目录名中含有空格,这时候$file就要带上引号否则就会报错 too many argument
C语言风格的for命令:
bash中c语言风格的for命令:
for(( varible assignment ; condition ; iteration process))
C语言风格的for命令允许为迭代使用多个变量循环会单独处理每个变量,尽管可以使用多个变量但你只能在for循环中定义一种条件。
#!/bin/bash
# multiple variable
for (( a=1,b=10 ; a<=10 ; a++ , b-- ))
do
echo " $a - $b "
done
while命令:
while命令的基本格式是:
while test command
do
other commands
done
while命令允许在while语句行定义多个测试命令,只有最后一个测试命令的退出状态码会被用来决定什么时候结束循环
#!/bin/bash
#testing a multicommand while loop
var1=10
while echo $var1
[ $var1 -ge 0 ] #-ge即为大于等于
do
echo "This is inside the loop"
var1=$[ $var1 - 1 ] #shell的算数运算操作格式为$[ ]
done
until命令:
until命令和while命令工作的方式完全相反。until命令要求你指定一个通常返回非零退出状态码的测试命令只有测试命令的退出状态码不为0,bash shell 才会执行循环中列出的命令一单测试命令返回了退出状态码0,循环就结束了。
( while循环返回退出状态码0则会继续执行循环 )
until test commands
do
other commands
done
#!/bin/bash
#using the util command
var1=100
until echo $var1
[ $var1 -eq 0 ]
do
echo Inside the loop: $var1
var1=$[ $var1 - 25 ]
done
shell会执行指定的多个测试命令,只有在最后的一个命令成立时才停止。
嵌套循环:(nestd loop)
for 嵌套 for:
#!/bin/bash
#using nestd loop
for( ( a=1 ; a<=3 ; a++ ) )
do
echo " Starting loop $a: "
for( ( b=1 ; b<=3 ; b++ ) )
do
echo " Inside loop : $b "
done
done
注意:两个循环的do和done没有任何区别,bash shell自身能够区别内部循环和外部循环。
while 嵌套 for:
#!/bin/bash
#a for loop inside a while loop
var1=5
while [ $var1 -ge 0 ]
do
echo "Outer loop: $var1 "
for ( ( var2=1 ; $var2 <3 ; var2++ ) )
do
var3 = $ [ $var1 * $var2 ]
echo " Inner loop: $var1 * $var2 = $var3 "
done
var1=$[ $var1 - 1 ]
done
同样shell能够区分for循环和while循环各自的do和done。
可以自行尝试while循环和until循环
循环处理文件数据:
通常必须遍历存储在文件中的数据,这要求结合两种技术:
1。使用嵌套循环
2。修改IFS环境变量
通过修改IFS环境变量,就能强制for命令将文件中的每行都当成单独的一个条目来处理,即便数据中有空格也是如此。一旦从文件中提取出了单独的行,可能需要再次利用循环来提取行中的数据。
典型的例子是处理/etc/passwd文件中的数据
IFS=$'\n' //使用换行符做为字段分隔符。
IFS='\n':;" //这个赋值会将反斜杠、n、冒号、分号和双引号作为字段分隔符。
IFS=$'\n':;" //这个赋值会将换行符、冒号、分号和双引号作为字段分隔符。
执行脚本得到如图所示结果
控制循环:
→break是退出循环的一个简单办法,可以用break命令来退出任意类型的循环
1. 跳出单个循环
2. 跳出内部循环
在处理多个循环时,break命令会自动禁止你所在的最内层的循环
如下例:
3. 跳出外部循环
有时你在内部循环,但需要停止外部循环。break命令接受单个命令行参数值:
break n
其中n指定了要跳出的循环层级,默认情况下n为1,表明跳出的是当前的循环。如果将n设为2,break命令就会停止下一级的外部循环。
注意:当shell执行了break命令后,外部循环就停止了。
continue命令:
continue命令可以提前终止某次循环中的命令,但并不会完全终止整个循环。可以在循环内部设置shell不执行命令的条件。
当if-then语句的条件被满足时(值大于5小于10),shell会执行continue命令,跳过当前循环中剩余的命令(本例中即为echo语句被跳过),但整个循环还会继续,所以显示了10-15的数字。
当shell执行continue命令时,它会跳过剩余的命令,如果你在某个条件里对测试条件变量进行增值,问题就出现了。
执行脚本你会发现出现了问题(本处将输出结果重定向到more),当shell执行continue命令时,它跳过了while循环中余下的命令,不幸的是,跳过的部分正是$var1计数变量增值的地方,而这个变量又被用于while测试命令中,这意味着这个变量值将不会再发生变化。
continue也允许通过命令行参数指定要继续执行哪一级循环:
continue n
处理循环的输出:
..........
done > output.txt
..........
done | sort
查找可执行文件: