《Linux Command Line and Shell Scripting Bible》Part 13 更多的结构化命令(for while until)
for命令
基本语法格式
for var in list
do
commands
done
也可以写成
for var in list; do
commands
done
读取列表中的值
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ ./test1
The next state Alabama
The next state Alaska
The next state Arizona
The next state Arkansas
The next state California
The next state Colorado
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ cat test1
#! /bin/bash
for test in Alabama Alaska Arizona Arkansas California Colorado
do
echo The next state $test
done
for循环结束,变量会保持最后一次的值,这个跟Python一样
读取列表中的复杂值
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ ./badtest1
word:I
word:dont know if thisll
word:work
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ cat badtest1
#! /bin/bash
for test in I don't know if this'll work
do
echo "word:$test"
done
shijianzhongdeMacBook-Pro:part_13 shijianzhong$
shell看到列表值中的单引号并尝试使用它们来定义一个单独的数据值。这可能不是你想要的
可以通过转义符号或者双引号解决
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ ./test2
word:I
word:don't
word:know
word:if
word:this'll
word:work
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ cat test2
#! /bin/bash
for test in I don\'t know if "this'll" work
do
echo "word:$test"
done
shijianzhongdeMacBook-Pro:part_13 shijianzhong$
从前面可以看出for循环中用空格分割,如果想显示有空格的数据,也可以通过双引号帮助
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ ./test3
Now going to Nevada
Now going to New Hampshire
Now going to New Mexico
Now going to New Tork
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ cat test3
#! /bin/bash
for test in Nevada "New Hampshire" "New Mexico" "New Tork"
do
echo "Now going to $test"
done
shijianzhongdeMacBook-Pro:part_13 shijianzhong$
从变量读取列表
将一系列值都集中存储在一个变量中,然后需要遍历变量中的整个列表[这里我犯了一个初级的错误,变量赋值的过程中如果不带引号,是不对的。系统把自动把空格当成分割]
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ ./test4
Alabama Alaska Arizona Arkansas Colorado
Have you ever visited Alabama
Have you ever visited Alaska
Have you ever visited Arizona
Have you ever visited Arkansas
Have you ever visited Colorado
Have you ever visited Connecticut
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ cat test4
#! /bin/bash
list="Alabama Alaska Arizona Arkansas Colorado"
echo $list
list=$list" Connecticut"
for state in $list
do
echo "Have you ever visited $state"
done
shijianzhongdeMacBook-Pro:part_13 shijianzhong$
从一个字符串中读取,遇到空格自动分割,还有一个字符串的合并不用任何符号,两个并列放一起就好
从命令读取值
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ ./test5
Visit baeutiful Alabama
Visit baeutiful ALska
Visit baeutiful Colorado
Visit baeutiful Commectiuct
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ cat test5
#! /bin/bash
file="states"
for state in $(cat $file)
do
echo "Visit baeutiful $state"
done
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ cat states
Alabama
ALska
Colorado
Commectiuct
shijianzhongdeMacBook-Pro:part_13 shijianzhong$
上面的字段,如果名字中有空格,还是会自动分割
更改字段分隔符
IFS 内部字段分隔符(internal field separator)
IFS环境变量定义了bash shell用作字段分割符的一系列字符。默认情况下为:空格,制表符, 换行符
如果要修改可以重新定义IFS=$'\n',这样IFS只能换行符了
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ ./test5b
Visit baeutiful Alabama ok
Visit baeutiful ALska
Visit baeutiful Colorado
Visit baeutiful Commectiuct
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ cat test5b
#! /bin/bash
file="states"
IFS=$'\n'
for state in $(cat $file)
do
echo "Visit baeutiful $state"
done
shijianzhongdeMacBook-Pro:part_13 shijianzhong$
如果要中间临时修改以下IFS,后面重新恢复原来的,可以中间使用一个临时变量
IFS.OLD=$IFS IFS=$'\n' #运行需要设定IFS的取悦 IFS=$IFS.OLD
如果要指定多个IFS分隔符,只要将它们赋值行穿起来就可以(注意,测试过了,只能用符号当分隔符,不用用字母)
IFS=$'\n':'
在mac上测试单引号与双引号没法设置成分隔符
用通配符读取目录
必须在文件名或路径名中使用通配符
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ ./test6
./badtest1 is a file
./states is a file
./test is a directory
./test1 is a file
./test2 is a file
./test3 is a file
./test4 is a file
./test5 is a file
./test5b is a file
./test6 is a file
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ cat test6
#! /bin/bash
for file in ./*
do
if [ -d "$file" ] # 判断是否是文件夹,加上双引号比较号,要不然碰到有空格的文件名,就会出现参数错误
then
echo "$file is a directory"
elif [ -f $file ] # 判断是否是文件
then
echo $file is a file
fi
done
shijianzhongdeMacBook-Pro:part_13 shijianzhong$
也可以使用多个目录通配符,并且合并在同一个for语句下
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ ./test7
./badtest1 is a file
./states is a file
./test is a directory
./test1 is a file
./test2 is a file
./test3 is a file
./test4 is a file
./test5 is a file
./test5b is a file
./test6 is a file
./test7 is a file
/no_way/heloo doesn't exist
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ cat test7
#! /bin/bash
for file in ./* /no_way/heloo # 匹配两个路径,中间用空格
do
if [ -d "$file" ] # 判断是否是文件夹,加上双引号比较号,要不然碰到有空格的文件名,就会出现参数错误
then
echo "$file is a directory"
elif [ -f $file ] # 判断是否是文件
then
echo $file is a file
else
echo "$file doesn't exist"
fi
done
shijianzhongdeMacBook-Pro:part_13 shijianzhong$
C语言风格的for命令
for (( variable ; condition; iteration process))
for (( a = 1; a < 10; a++))
这样的for循环有如下特点,变量赋值可以有空格,条件表达式中的变量可以不以$符开头,迭代过程的算式未用expr命令格式
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ ./test8
The next num is 1
The next num is 2
The next num is 3
The next num is 4
The next num is 5
The next num is 6
The next num is 7
The next num is 8
The next num is 9
The next num is 10
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ cat test8
#! /bin/bash
for (( i=1; i<=10; i++))
do
echo "The next num is $i"
done
shijianzhongdeMacBook-Pro:part_13 shijianzhong$
C语言风格的for命令也允许为迭代使用多个变量。循环会单独处理每个变量,你可以为每个变量定义不通的迭代过程。可以使用多个变量,但你只能在for循环中定义一种条件
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ ./test9
1 - 5
2 - 4
3 - 3
4 - 2
5 - 1
6 - 0
7 - -1
8 - -2
9 - -3
10 - -4
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ cat test9
#! /bin/bash
for (( a=1, b=5; a <=10; a++, b-- ))
do
echo "$a - $b"
done
shijianzhongdeMacBook-Pro:part_13 shijianzhong$
while 命令
while命令的格式是
while test command
do
other commands
done
test command 一般用[ ]来检测里面的值
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ ./test10
10
9
8
7
6
5
4
3
2
1
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ cat test10
#! /bin/bash
var1=10
while [ $var1 -gt 0 ] # 大于0的情况
do
echo $var1
var1=$[ $var1 - 1 ]
done
shijianzhongdeMacBook-Pro:part_13 shijianzhong$
使用多个测试命令
while命令允许你在while语句行定义多个测试命令。只有最后一个测试命令的退出状态码会被用来决定什么时候结束循环。是最后一个状态
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ ./test11
10
This is inside the loop
9
This is inside the loop
8
This is inside the loop
7
This is inside the loop
6
This is inside the loop
5
This is inside the loop
4
This is inside the loop
3
This is inside the loop
2
This is inside the loop
1
This is inside the loop
0
This is inside the loop
-1
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ cat test11
#! /bin/bash
var1=10
while echo $var1 # 条件1
[ $var1 -ge 0 ] # 条件2
do
echo "This is inside the loop"
var1=$[ $var1 - 1 ]
done
shijianzhongdeMacBook-Pro:part_13 shijianzhong$
13.4 until命令
until test commands
do
other commands
done
跟while一样,只不过这个是在条件不成立的时候执行,也就是test commands退出值不是0的时候执行,使用方式跟while基本一样
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ ./test12
100
75
50
25
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ cat test12
#! /bin/bash
var1=100
until [ $var1 -eq 0 ]
do
echo $var1
var1=`expr $var1 - 25`
done
shijianzhongdeMacBook-Pro:part_13 shijianzhong$
同样使用多个测试命令
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ ./test13
100
Inside the loop: 100
75
Inside the loop: 75
50
Inside the loop: 50
25
Inside the loop: 25
0
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ cat test13
#! /bin/bash
var1=100
until echo $var1
[ $var1 -eq 0 ]
do
echo Inside the loop: $var1
var1=`expr $var1 - 25`
done
shijianzhongdeMacBook-Pro:part_13 shijianzhong$
13.5嵌套循环
对于学过其他语言的,非常容易理解
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ ./test14
Starting loop 1:
Inside loop: 1
Inside loop: 2
Inside loop: 3
Starting loop 2:
Inside loop: 1
Inside loop: 2
Inside loop: 3
Starting loop 3:
Inside loop: 1
Inside loop: 2
Inside loop: 3
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ cat test14
#! /bin/bash
for (( a = 1; a <= 3; a++ ))
do
echo "Starting loop $a:"
for (( b = 1; b <= 3; b++ )) # 内层的循环
do
echo " Inside loop: $b"
done
done
shijianzhongdeMacBook-Pro:part_13 shijianzhong$
双层循环,while循环内套for循环
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ ./test15
Outer loop: 5
Inner loop: 5 * 1 = 5
Inner loop: 5 * 2 = 10
Outer loop: 4
Inner loop: 4 * 1 = 4
Inner loop: 4 * 2 = 8
Outer loop: 3
Inner loop: 3 * 1 = 3
Inner loop: 3 * 2 = 6
Outer loop: 2
Inner loop: 2 * 1 = 2
Inner loop: 2 * 2 = 4
Outer loop: 1
Inner loop: 1 * 1 = 1
Inner loop: 1 * 2 = 2
Outer loop: 0
Inner loop: 0 * 1 = 0
Inner loop: 0 * 2 = 0
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ cat ./test15
#! /bin/bash
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=`expr $var1 - 1`
done
shijianzhongdeMacBook-Pro:part_13 shijianzhong$
最后抄写书中一个until与while混用的循环
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ ./test16
Outer loop: 3
Inner loop: 3/ 1 = 3.0000
Inner loop: 3/ 2 = 1.5000
Inner loop: 3/ 3 = 1.0000
Inner loop: 3/ 4 = .7500
Outer loop: 2
Inner loop: 2/ 1 = 2.0000
Inner loop: 2/ 2 = 1.0000
Inner loop: 2/ 3 = .6666
Inner loop: 2/ 4 = .5000
Outer loop: 1
Inner loop: 1/ 1 = 1.0000
Inner loop: 1/ 2 = .5000
Inner loop: 1/ 3 = .3333
Inner loop: 1/ 4 = .2500
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ cat test16
#! /bin/bash
var1=3
until [ $var1 -eq 0 ] # 只要不等于0就执行
do
echo "Outer loop: $var1"
var2=1
while [ $var2 -lt 5 ] # 小于5执行
do
var3=$(echo "scale=4; $var1 / $var2" | bc)
echo " Inner loop: $var1/ $var2 = $var3"
var2=$[ $var2 + 1 ] # 执行内部逻辑
done
var1=$[ $var1 - 1 ] # 外部的逻辑执行
done
shijianzhongdeMacBook-Pro:part_13 shijianzhong$
话说里面的小数乘除法我又忘记了
循环处理文件数据
就是通过修改IFS的值来设定分隔符
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ cat ifs.sh
#! /bin/bash
IFS.OLD=$IFS
IFS=$'\n'
for entry in `cat /etc/passwd`
do
echo "Values in $entry -"
IFS=:
for value in $entry
do
echo " ${value}"
done
done
我的参数里面有*到时候输出的时候会出现问题,暂时没有好的办法搞定
控制循环
break与continue命令,这个用法跟Python也差不多
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ ./test17
Iteration number: 1
Iteration number: 2
Iteration number: 3
Iteration number: 4
The for loop is completed
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ cat test17
#! /bin/bash
for var1 in {1..10}
do
if [ $var1 -eq 5 ]
then
break
fi
echo "Iteration number: $var1"
done
echo "The for loop is completed"
shijianzhongdeMacBook-Pro:part_13 shijianzhong$
break 同样支持while和until,不写了,用法一模一样
跳出内部循环,单个break会跳出单个循环
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ chmod u+x test19
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ ./test19
Outer loop: 1
Inner loop: 1
Inner loop: 2
Inner loop: 3
Inner loop: 4
Outer loop: 2
Inner loop: 1
Inner loop: 2
Inner loop: 3
Inner loop: 4
Outer loop: 3
Inner loop: 1
Inner loop: 2
Inner loop: 3
Inner loop: 4
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ cat test19
#! /bin/bash
for ((a=1; a<4; a++))
do
echo "Outer loop: $a"
for ((b=1;b<100;b++))
do
if [ $b -eq 5 ] # 等于5
then
break # 暂停
fi
echo " Inner loop: $b"
done
done
shijianzhongdeMacBook-Pro:part_13 shijianzhong$
跳出外部循环
break n,默认没有参数为1
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ ./test20
Outer loop: 1
Inner loop: 1
Inner loop: 2
Inner loop: 3
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ cat test20
#! /bin/bash
for ((a=1; a<4; a++))
do
echo "Outer loop: $a"
for ((b=1;b<100;b++))
do
if [ $b -eq 4 ] # 等于5
then
break 3 # 暂停
fi
echo " Inner loop: $b"
done
done
shijianzhongdeMacBook-Pro:part_13 shijianzhong$
书中break写了2,我写了3也没是,看来多写是没关系的。
continue命令
continue用法跟Python这种差不多,也就多了一个continue n就是外部也不执行命令
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ ./test21
Iteration number: 1
Iteration number: 2
Iteration number: 3
Iteration number: 4
Iteration number: 5
Iteration number: 10
Iteration number: 11
Iteration number: 12
Iteration number: 13
Iteration number: 14
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ cat test21
#! /bin/bash
for (( var1=1;var1<15;var1++))
do
if [ $var1 -gt 5 ] && [ $var1 -lt 10 ] # 5<var1<10
then
continue
fi
echo "Iteration number: $var1"
done
shijianzhongdeMacBook-Pro:part_13 shijianzhong$
处理循环的输出
循环的最后输出可以在done后面使用管道或者重定向>
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ cat test23.txt
The number is 1
The number is 2
The number is 3
The number is 4
The number is 5
The number is 6
The number is 7
The number is 8
The number is 9
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ cat test23
#! /bin/bash
for ((a=1;a<10;a++))
do
echo "The number is $a"
done > test23.txt
shijianzhongdeMacBook-Pro:part_13 shijianzhong$
还有一种通过管道输出
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ ./test24
Alabama is the next place to go
Connecticut is the next place to go
Illinois is the next place to go
North Dakote is the next place to go
Tennessee is the next place to go
This completes our place to go
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ cat test24
#! /bin/bash
for state in "North Dakote" Connecticut Illinois Alabama Tennessee
do
echo "$state is the next place to go"
done | sort
echo "This completes our place to go"
shijianzhongdeMacBook-Pro:part_13 shijianzhong$
演示实例,查找PATH中的可执行文件
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ echo $PATH /usr/local/opt/mysql@5.7/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin shijianzhongdeMacBook-Pro:part_13 shijianzhong$
从输出可以看出路径是用:分割的,开始抄写代码编写注释
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ cat test25
#! /bin/bash
IFS.OLD=$IFS
IFS=:
for folder in $PATH # 循环读取环境
do
echo "$folder:"
for file in $folder/* # 读取文件
do
if [ -x $file ] # 判断文件是否可执行
then
echo " $file"
fi
done
done
shijianzhongdeMacBook-Pro:part_13 shijianzhong$
创建多个用户账户,涉及到读取文件操作
shijianzhongdeMacBook-Pro:part_13 shijianzhong$ cat test26
#! /bin/bash
input="users.csv"
while IFS=',' read -r userid name # 从文件读取后,设置了IFS,读取了两个参数
do
echo "adding $userid"
useradd -c "$name" -m "$userid" # 创建用户
done < "$input" # 通过<重定向符输入读取的文件
shijianzhongdeMacBook-Pro:part_13 shijianzhong$
上面的代码,重点是while 循环中,分隔符的设置,以及read -r读取重定向符指定的文件
小结
无,稍微写一点点,就是何为条件为真执行,就是退出状态码为0
浙公网安备 33010602011771号