Skip to content

更多结构化命令

for命令

bash
for var in list 
do 
	commands 
done

在每次迭代中,变量var会包含列表中的当前值。第一次迭代会使用列表中的第一个值,第二次迭代使用第二个值,以此类推,直到列表中的所有值都过一遍

和python中的迭代一样

读取列表中的值

读取自己定义的列表

bash
  1 #!/bin/bash                                                                           
  2 for test in Alabama Alaska Arizona Arkansas California Colorado 
  3 do  
  4     echo The next state is $test 
  5 done
  
jiao@jiao-virtual-machine:~/桌面/linux-shell/13$ test.sh
The next state is Alabama
The next state is Alaska
The next state is Arizona
The next state is Arkansas
The next state is California
The next state is Colorado

test会保留最后一次循环的值

读取列表的复杂值

bash
  1 #!/bin/bash                                                                           
  2 
  3 for test in I don't know if this'll work 
  4 do
  5     echo "word:$test" 
  6 done
  7 #another example of how not to use the 
  8 for test in I don\'t know if "this'll" work
  9 do
 10     echo "word:$test" 
 11 done
 
 
jiao@jiao-virtual-machine:~/桌面/linux-shell/13$ test2.sh
word:I
word:dont know if thisll
word:work
word:I
word:don't
word:know
word:if
word:this'll
word:work

会把存在的引号当做分割的符号, 可以使用转义字符, 或者使用另一种引号引起来

for循环假定所有的分割都使用的空格, 如果有的值中间存在空格要使用引号引起来

bash
  1 #!/bin/bash                                                                           
  2 for test in Nevada "New Hampshire" "New Mexico" "New York" "North Carolina"
  3 do 
  4     echo $test
  5 done
  
jiao@jiao-virtual-machine:~/桌面/linux-shell/13$ test3.sh 
Nevada
New Hampshire
New Mexico
New York
North Carolina

从变量读取列表

把值存放在一份列表之中

bash
  1 #!/bin/bash                                                                           
  2 list="Alabama Alaska Arizona Arkansas Colorado"
  3 for test in $list
  4 do
  5     echo "Have you ever visted $test"
  6 done

jiao@jiao-virtual-machine:~/桌面/linux-shell/13$ test4.sh 
Have you ever visted Alabama
Have you ever visted Alaska
Have you ever visted Arizona
Have you ever visted Arkansas
Have you ever visted Colorado

从命令读取值

生成列表中所需值的另外一个途径就是使用命令的输出。可以用命令替换来执行任何能产生输出的命令,然后在for命令中使用该命令的输出

bash
  1 #!/bin/bash                                                                           
  2 file="state"
  3 for state in $(cat $file)
  4 do
  5     echo "Visit beautiful $state"
  6 done
# state文件
  1 Alabama                                                                               
  2 Alaska 
  3 Arizona 
  4 Arkansas
  5 Colorado
  6 Connecticut
  7 Delaware
  8 Florida
  9 Georgia

jiao@jiao-virtual-machine:~/桌面/linux-shell/13$ test5.sh 
Visit beautiful Alabama
Visit beautiful Alaska
Visit beautiful Arizona
Visit beautiful Arkansas
Visit beautiful Colorado
Visit beautiful Connecticut
Visit beautiful Delaware
Visit beautiful Florida
Visit beautiful Georgia

更换字段的分隔符

环境变量IFS, 叫做内部字段分隔符, 定义了bash shell作为分隔符的一些列字符, 通常为

  • 空格
  • 制表符
  • 换行符

要想只识别换行符, IFS=$'\n'

bash
  1 #!/bin/bash                                                                           
  2 # reading values from a file 
  3 file="states" 
  4 IFS=$'\n'
  5 for state in $(cat $file)
  6 do
  7     echo $state 
  8 done

jiao@jiao-virtual-machine:~/桌面/linux-shell/13$ test6.sh 
Visit beautiful Alabama
Visit beautiful Alaska
Visit beautiful Arizona
Visit beautiful Arkansas
Visit beautiful Colorado
Visit beautiful Connecticu
Visit beautiful Delaware
Visit beautiful Florida
Visit beautiful Georgia
Visit beautiful New York
Visit beautiful New Hampshire
Visit beautiful North Carolina

最好再更改之前对IFS的值进行保存

bash
  IFS.OLD=$IFS   
  IFS=$'\n'   
  <在代码中使用新的IFS值>   
  IFS=$IFS.OLD

可以设置多个分隔符, 只需要串起来

bash
IFS=$'\n':;"

使用换行符, 冒号, 分号, 双引号为分隔符

用通配符读取目录

可以使用for命令来遍历目录中的文件,

进行此操作时,必须在文件名或路径名中使用通配符。它会强制shell使用文件扩展匹配。

bash
  1 #!/bin/bash                                                                           
  2 for file in /home/jiao/*
  3 do 
  4     if [ -d "$file" ]
  5     then echo "$file is a dictory"
  6     elif [ -f "$file" ]
  7     then echo "$file is a dictory"
  8     fi
  9 done
  
jiao@jiao-virtual-machine:~/桌面/linux-shell/13$ test7.sh 
/home/jiao/01_Python is a dictory
/home/jiao/公共的 is a dictory
/home/jiao/模板 is a dictory
/home/jiao/视频 is a dictory
/home/jiao/图片 is a dictory
/home/jiao/文档 is a dictory
/home/jiao/下载 is a dictory
/home/jiao/音乐 is a dictory
/home/jiao/桌面 is a dictory
/home/jiao/Makefile is a dictory
/home/jiao/snap is a dictory

在Linux文件名包含空格是合法的, 所以为了适应, 用引号括起来

也可以在for命令中列出多个目录通配符,将目录查找和列表合并进同一个for语句

bash
for file in /home/rich/.b* /home/rich/badtest

C语言风格的for语句

bash
for (( variableassignment ; condition ; iterationprocess ))
bash
  1 #!/bin/bash                                                                           
  2 for (( i=1 ; i<10 ; i++ ))
  3 do 
  4     echo "The next is $i"
  5 done


jiao@jiao-virtual-machine:~/桌面/linux-shell/13$ test8.sh 
The next is 1
The next is 2
The next is 3
The next is 4
The next is 5
The next is 6
The next is 7
The next is 8
The next is 9

使用多个变量

也允许为迭代使用多个变量。循环会单独处理每个变量,你可以为每个变量定义不同的迭代过程。尽管可以使用多个变量,但你只能在for循环中定义一种条件

for (( a=1, b=10; a <= 10; a++, b-- ))

while命令

只要定义的测试命令的代码返回值是0, 就一直进行循环

while的基本格式

bash
while testcommand 
do 
	othercommands 
done

while命令中定义的test command和if-then语句中的格式一模一样, 可以使用任何普通的bash shell命令,或者用test命令进行条件测试

bash
  1 #!/bin/bash                                                                           
  2 val1=10
  3 while [ $val1 -gt 0 ] # 这里用的是test命令的中括号
  4 do
  5     echo $val1
  6     val1=$[ $val1 - 1 ]   # 这里使用的是浮点数计算时候讲的中括号
  7 done

使用多个测试命令

while命令允许你在while语句行定义多个测试命令。只有最后一个测试命令的退出状态码会被用来决定什么时候结束循环。

bash
  1 #!/bin/bash                                                                           
  2 var1=10
  3 while echo $var1
  4         [ $var1 -ge 0 ]
  5 do
  6     echo "This is inside loop"
  7     var1=$[ $var1 - 1 ]
  8 done
  
jiao@jiao-virtual-machine:~/桌面/linux-shell/13$ test10.sh 
10
This is inside loop
9
This is inside loop
8
This is inside loop
7
This is inside loop
6
This is inside loop
5
This is inside loop
4
This is inside loop
3
This is inside loop
2
This is inside loop
1
This is inside loop
0
This is inside loop
-1

注意,每个测试命令都出现在单独的一行上

until命令

测试命令码不为0的时候进行循环, 不为0的时候退出循环

bash
until test command
do
	other commands
done
bash
  1 #!/bin/bash                                                                           
  2 
  3 var1=100
  4 until [ $var1 -eq 0 ]
  5 do
  6     echo $var1
  7     var1=$[ $var1 - 25 ]
  8 done

嵌套循环

bash
 10 for (( a = 1; a <= 3; a++ ))
 11 do
 12     echo "Start loop $a:"
 13     for (( b=1; b<=3; b++ ))
 14     do echo " Inside loop: $b"
 15     done
 16 done

循环处理文件数据

bash
  1 #!/bin/bash                                                                           
  2 
  3 IFS.OLD=$IFS
  4 IFS=$'\n'
  5 for entry in $(cat /etc/passwd) # 这里已经把结果分割为多个值了
  6 do
  7     echo "Value in $entry -"
  8     IFS=:
  9     for value in $entry
 10     do
 11         echo "      $value"
 12     done
 13 done

Value in jiao:x:1000:1000:jiao,,,:/home/jiao:/bin/bash -
      jiao
      x
      1000
      1000
      jiao,,,
      /home/jiao
      /bin/bash

控制循环

  • break
  • continue

break

跳出单次循环

跳出内层循环

跳出外层循环

有时你在内部循环,但需要停止外部循环。break命令接受单个命令行参数值

bash
break n

n为1, 跳出挡圈循环, 2跳出下一层

bash
  1 #!/bin/bash                                                                           
  2 
  3 for ((a=0;a<4;a++))
  4 do
  5     echo "Outer loop $a"
  6     for ((b=1;b<100;b++))
  7     do
  8         if [ $b -gt 4 ]
  9         then
 10             break 2
 11         fi
 12         echo "      Inner loop $b"
 13     done
 14 done

jiao@jiao-virtual-machine:~/桌面/linux-shell/13$ test14.sh 
Outer loop 0
      Inner loop 1
      Inner loop 2
      Inner loop 3
      Inner loop 4

continue命令

也可以使用数字, 用来停止外部的循环

处理循环输出

bash
  1 #!/bin/bash                                                                           
  2 for ((a=1;a<10;a++))
  3 do
  4     echo "The number is $a"
  5 done > test.txt				# 输出到一个文件中
  6 echo "The command is finish"
  • 同样使用于管道
bash
  1 #!/bin/bash                                                                           
  2 
  3 for state in "North Dakota" Connecticut Illinois Alabama Tennessee 
  4 do
  5     echo "$state is the next place to go"
  6 done | sort
  7 echo "This conplete our travel"

实例

查找可执行的文件

查找PATH下的所有可执行文件

bash
  1 #!/bin/bash                                                                           
  2 IFS=:
  3 for floder in $PATH
  4 do
  5     for file in $floder/*
  6     do
  7         if [ -x $file ]
  8         then
  9             echo "    $file"
 10         fi
 11     done
 12 done

创建多个用户账户

csv格式保存用户的id以及用户的名字

bash
  1 #!/bin/bash                                                                           
  2 
  3 input="users.csv"
  4 while IFS=',' read -r userid name		# 下一
  5 do
  6     echo "add $userid"
  7     useradd -c "$name" -m $userid
  8 done < "$input"