13 更多的结构化命令

13.1 for命令

基本用法

for var in list; do
commands
done

注意for遍历完之后,循环变量的值还剩下的shell脚本中还能访问

#!/bin/bash
# basic for command
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"
leo@ubuntu:~/sh_test$ ./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
The last state we visited was Colorado
Wait, now we're visiting Connecticut

处理空格和引号

for是按照空格开区分变量的,如果一个变量内包含空格,需要用双引号分开。如果有单引号,可以使用转义字符,也可以用双引号。

#!/bin/bash
# basic for command
for test in I don\'t know if "I'll" go to "New York"; do
echo $test
done
leo@ubuntu:~/sh_test$ ./test.sh
I
don't
know
if
I'll
go
to
New York

从变量或文件中读取值

# !/bin/bash
# using a variable to hold a list
list="Alabama Alaska Arizona Arkansas Colorado"
list=$list" Connecticut"
for state in $list; do
echo "Have you ever visited $state?"
done
leo@ubuntu:~/sh_test$ ./test.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 Colorado?
Have you ever visited Connecticut?
# !/bin/bash
# reading from a file
file="./states"
for state in $(cat $file); do
echo "Visit beautiful $state"
done
leo@ubuntu:~/sh_test$ ./test.sh
Visit beautiful Alabama
Visit beautiful Alaska
Visit beautiful Arizona
Visit beautiful Arkansas
Visit beautiful Colorado
Visit beautiful Connecticut

文件states

Alabama
Alaska
Arizona
Arkansas
Colorado
Connecticut

IFS(internal field separator)

shell默认会以空格制表符换行符作为字段分隔符。但是如果我们指定了IFS,则会以IFS指定的分隔符进行分隔

# !/bin/bash
# reading from a file
test="I am:You are:She is"
IFS=:
for item in $test; do
echo "item is: $item"
done
leo@ubuntu:~/sh_test$ ./test.sh
item is: I am
item is: You are
item is: She is

一种临时指定IFS的用法

IFS.OLD=$IFS
IFS=$'\n'
...
IFS=$IFS.OLD

下面指定了换行符冒号分号双引号作为分隔符

IFS=$'\n':;"

用通配符读取目录

如果在文件名或路径是使用通配符,则for命令会自动变量目录中的文件

# !/bin/bash
# iterate through all the files in a directory
for file in /home/leo/*; do
if [ -d "$file" ]; then
echo "$file is a directory"
elif [ -f "$file" ]; then
echo "$file is a file"
fi
done
leo@ubuntu:~/sh_test$ ./test.sh
/home/leo/c_test is a directory
/home/leo/dev is a directory
/home/leo/examples.desktop is a file

还可以把通配符的路径和普通路径写到同一个for里面

# !/bin/bash
# iterate through all the files in a directory
for file in /home/leo/* /home/leo/badtest; do
if [ -d "$file" ]; then
echo "$file is a directory"
elif [ -f "$file" ]; then
echo "$file is a file"
else
echo "$file does not exit"
fi
done
leo@ubuntu:~/sh_test$ ./test.sh
/home/leo/c_test is a directory
/home/leo/dev is a directory
/home/leo/examples.desktop is a file
/home/leo/badtest does not exit

13.2 C风格的for命令

# !/bin/bash
# testing c-style for loop
for (( a=1, b=10; a <= 10; a++, b--)); do
echo "$a - $b"
done
leo@ubuntu:~/sh_test$ ./test.sh
1 - 10
2 - 9
3 - 8
4 - 7
5 - 6
6 - 5
7 - 4
8 - 3
9 - 2
10 - 1

13.3 while命令

while命令在条件中可以写多个语句。只有最后一个语句的退出状态码会被用来决定什么时候结束循环。

# !/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
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