13.1 for 命令
格式:
for var in list
do
commands
done
for var in list; do
commands
done
13.1.1 读取列表中的值
#!/bin/bash
# basic for command
for test in Alabama Alaska Arizona Arkansas California Colorado
do
echo The next state is $test
done
- for 循环结束后, test 会保持 list 中最后一个值
- 可以在 for 之外使用 test
#!/bin/bash
# testing the for variable after the looping
for test in Alabama Alaska Arizona Arkansas California Colorado
do
echo "The next state is $test"
done
echo "The last state we visited was $test"
test=Connecticut
echo "Wait, now we're visiting $test"
13.1.2 读取列表中的复杂值
list 中使用单引号:
#!/bin/bash
# another example of how not to use the for command
for test in I don\'t know if "this'll" work
do
echo "word:$test"
done
- list 中的某个值包括空格的话, 使用双引号
13.1.3 从变量读取列表
#!/bin/bash
# using a variable to hold the list
list="Alabama Alaska Arizona Arkansas California Colorado"
list=$list" Connecticut"
for state in $list
do
echo "Have you ever visited $state?"
done
输出:
$ ./my_script.sh
Have you ever visited Alabama?
Have you ever visited Alaska?
Have you ever visited Arizona?
Have you ever visited Arkansas?
Have you ever visited California?
Have you ever visited Colorado?
Have you ever visited Connecticut?
13.1.4 从命令读取值
#!/bin/bash
# reading values from a file
file="states"
for state in $(cat $file)
do
echo "Visit beautiful $state"
done
13.1.5 更改字段分隔符
IFS, 内部字段分隔符 (internal field separator), 默认值:
- 空格
- 制表符
- 换行符
IFS=$'\n'
一个可参考的安全实践是在改变 IFS 之前保存原来的 IFS 值, 之后再恢复它。
IFS.OLD=$IFS
IFS=$'\n'
<在代码中使用新的 IFS 值>
IFS=$IFS.OLD
定义多个分隔符:
- 换行
- 冒号
- 分号
- 双引号
IFS=$'\n':;"
13.1.6 用通配符读取目录
- 如果目录名或文件名中含有空格, 那么应该使用
"$file"
形式 (双引号)
#!/bin/bash
# iterate through all the files in a directory
for file in /home/rich/test/*
do
if [ -d "$file" ]
then
echo "$file is a directory"
elif [ -f "$file" ]
then
echo "$file is a file"
fi
done
in 后面可以使用多个值
#!/bin/bash
# iterating through multiple directory
for file in /home/rich/.b* /home/rich/badtest
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
13.2 C 语言风格的 for 命令
13.2.1 C 语言的 for 命令
格式:
- 引用变量没有使用
$
符号
for (( variable assignment ; condition ; iteration process ))
例子:
for (( a = 1; a < 10; a++ ))
注意:
- 变量赋值可以有空格
- 条件中的变量不以美元符开头
- 迭代过程的算式未用 expr 命令格式
使用:
#!/bin/bash
# testing the C-style for loop
for (( i=1; i <= 10; i++ ))
do
echo "The next number is $i"
done
13.2.2 使用多个变量
- 但是只能定义一种条件
#!/bin/bash
# multiple variables
for (( a=1, b=10; a <= 10; a++, b-- ))
do
echo "$a - $b"
done
13.3 while 命令
- 测试退出状态码
13.3.1 while 的基本格式
while test command
do
other commands
done
- 如果退出状态码不变, 那么进入死循环
- test 可以使用
[]
替代
#!/bin/bash
# while command test
var1=10
while [ $var1 -gt 0 ]
do
echo $var1
var1=$[ $var1 - 1 ]
done
13.3.2 使用多个测试命令
- 只有最后一个测试命令的退出状态码会被用来决定什么时候结束循环
- 每个测试命令在单独一行
- 每个测试都会执行
**
#!/bin/bash
# testing a multicommand while loop
var1=10
while echo $var1
[ $var1 -ge 0 ]
do
echo "This is inside the loop"
var1=$[ $var1 - 1 ]
done
13.4 until 命令
- 只有测试命令的退出状态码不为0才会执行循环
格式:
- 也可以指定多个测试命令
until test commands
do
other commands
done
使用:
#!/bin/bash
# using the until command
var1=100
until [ $var1 -eq 0 ]
do
echo $var1
var1=$[ $var1 - 25 ]
done
13.5 嵌套循环
#!/bin/bash
# nesting for loops
for (( a = 1; a <= 3; a++ ))
do
echo "Starting loop $a:"
for (( b = 1; b <= 3; b++ ))
do
echo " Inside loop: $b"
done
done
#!/bin/bash
# placing 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
#!/bin/bash
# using until and while loops
var1=3
until [ $var1 -eq 0 ]
do
echo "Outer loop: $var1"
var2=1
while [ $var2 -lt 5 ]
do
var3=$(echo "scale=4; $var1 / $var2" | bc)
echo " Inner loop: $var1 / $var2 = $var3"
var2=$[ $var2 + 1 ]
done
var1=$[ $var1 - 1 ]
done
13.6 循环处理文件数据
- 原例子没有回复 IFS
#!/bin/bash
# changing the IFS value
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
13.7 控制循环
13.7.1 break 命令
1. 跳出单个循环
#!/bin/bash
# breaking out of a for loop
for var1 in 1 2 3 4 5 6 7 8 9 10
do
if [ $var1 -eq 5 ]
then
break
fi
echo "Iteration number: $var1"
done
echo "The for loop is completed"
2. 跳出内部循环
#!/bin/bash
# breaking out of an inner loop
for (( a = 1; a < 4; a++ ))
do
echo "Outer loop: $a"
for (( b = 1; b < 100; b++ ))
do
if [ $b -eq 5 ]
then
break
fi
echo " Inner loop: $b"
done
done
3. 跳出外部循环
格式:
n
指定要跳出的层级- 1: 当前循环
break n
使用:
#!/bin/bash
# breaking out of an outer loop
for (( a = 1; a < 4; a++ ))
do
echo "Outer loop: $a"
for (( b = 1; b < 100; b++ ))
do
if [ $b -gt 5 ]
then
break 2
fi
echo " Inner loop: $b"
done
done
13.7.2 continue 命令
#!/bin/bash
# using the continue command
for (( var1 = 1; var1 < 15; var1++ ))
do
if [ $var1 -gt 5 ] && [ $var1 -lt 10 ]
then
continue
fi
echo "Iteration number: $var1"
done
也允许使用层级:
continue n
13.8 处理循环的输出
对循环的输出使用管道或进行重定向:
for file in /home/rich/*
do
if [ -d "$file" ]
then
echo "$file is a directory"
elif
echo "$file is a file"
fi
done > output.txt # done | sort
13.9 实例
13.9.1 查找可执行文件
#!/bin/bash
# finding files in the PATH
IFS=:
for folder in $PATH
do
echo "$folder:"
for file in $folder/*
do
if [ -x $file]
then
echo " $file"
fi
done
done
13.9.2 创建多个用户账户
#!/bin/bash
# process new user accounts
input="users.csv"
while IFS=',' read -r userid name
do
echo "adding $userid"
useradd -C "$name" -m $userid
done < "$input"