文章目录
一、Shell 流程控制
Shell 脚本中的流程控制结构允许你根据条件执行不同的代码块,或者重复执行某些代码块。这些结构包括 if
语句、for
循环、while
循环和 case
语句等。
二、If 语句
在 Shell 脚本中,if
语句用于根据条件执行不同的代码块。如果条件为真(返回值为 0),则执行 then
后面的代码块;如果条件为假(返回值非 0),则可以选择性地执行 else
或 elif
后面的代码块。
if
语句的基本语法如下:
if [ condition ]
then
# 条件为真时执行的代码块
else
# 条件为假时执行的代码块(可选)
fi
你还可以使用 elif
来添加额外的条件检查:
if [ condition1 ]
then
# condition1 为真时执行的代码块
elif [ condition2 ]
then
# condition1 为假,但 condition2 为真时执行的代码块
else
# 所有条件都不为真时执行的代码块(可选)
fi
在条件表达式中,[ ]
是测试命令的语法,用于评估条件。注意,[ ]
两边都需要有空格。此外,你也可以使用 [[ ]]
,它在一些现代的 shell(如 bash)中提供了更多的功能和更好的字符串比较能力。
以下是一些 if
语句的使用示例:
示例 1:检查文件是否存在
#!/bin/bash
file="/path/to/file"
if [ -f "$file" ]; then
echo "文件 $file 存在."
else
echo "文件 $file 不存在."
fi
示例 2:比较整数
#!/bin/bash
num1=10
num2=20
if [ $num1 -lt $num2 ]; then
echo "$num1 小于 $num2"
fi
示例 3:使用 elif
#!/bin/bash
read -p "请输入一个整数: " num
if [ $num -eq 0 ]; then
echo "你输入的是零."
elif [ $num -gt 0 ]; then
echo "你输入的是正数."
else
echo "你输入的是负数."
fi
示例 4:检查字符串是否相等
#!/bin/bash
str1="hello"
str2="world"
if [ "$str1" = "$str2" ]; then
echo "字符串相等."
else
echo "字符串不相等."
fi
示例 5:使用双括号进行算术比较
在 bash 中,你可以使用双括号 (( ))
进行算术扩展和比较:
#!/bin/bash
num1=5
num2=10
if (( num1 < num2 )); then
echo "$num1 小于 $num2"
fi
在使用 if
语句时,条件表达式中的变量和操作符之间必须有空格,否则脚本可能会因为解析错误而失败。
三、For 循环
在 Shell 脚本中,for
循环用于遍历一个序列,并对序列中的每个元素执行一段代码。Shell 提供了几种不同的 for
循环语法,包括 for...in
循环和 C 风格的 for
循环(使用 (( ))
进行算术扩展)。
- for…in 循环
for...in
循环用于遍历列表或字符串中的元素。
案例:遍历一个字符串列表,并打印每个元素。
#!/bin/bash
# 定义一个字符串列表
fruits=("apple" "banana" "cherry")
# 使用 for...in 循环遍历列表
for fruit in "${fruits[@]}"
do
echo "$fruit"
done
在这个例子中,${fruits[@]}
表示数组 fruits
中的所有元素。do
和 done
之间的代码块会对数组中的每个元素执行一次。
- C 风格的 for 循环
C 风格的 for
循环通常用于算术序列的迭代。它使用 (( ))
语法进行算术扩展。
案例:从 1 数到 5。
#!/bin/bash
# 使用 C 风格的 for 循环
for (( i=1; i<=5; i++ ))
do
echo "$i"
done
在这个例子中,for (( i=1; i<=5; i++ ))
定义了一个循环,变量 i
从 1 开始,每次循环增加 1,直到 i
大于 5 为止。循环体中的代码块会对每个 i
的值执行一次。
- 遍历文件或目录
for
循环也常用于遍历文件或目录。
案例:遍历一个目录中的所有文件,并打印文件名。
#!/bin/bash
# 指定目录路径
directory="/path/to/directory"
# 使用 for 循环遍历目录中的文件
for file in "$directory"/*
do
if [ -f "$file" ]; then
echo "$file"
fi
done
在这个例子中,"$directory"/*
会展开为指定目录中的所有文件和子目录。if [ -f "$file" ]; then
检查 $file
是否为一个普通文件,如果是,则打印文件名。
注意事项
- 当使用
for...in
循环遍历字符串时,如果字符串中包含空格或特殊字符,它们会被当作分隔符。如果需要处理包含空格的字符串,可以使用引号将变量括起来,如"${variable}"
。 - 在 C 风格的
for
循环中,所有的算术操作都在(( ))
中进行,这样可以避免字符串和算术之间的混淆。 - 在循环内部,可以使用
break
语句提前退出循环,或者使用continue
语句跳过当前迭代并进入下一个迭代。
四、While 循环
在 Shell 脚本中,while
语句用于创建一个循环,该循环会持续执行一段代码,直到指定的条件不再满足为止。每次循环迭代时,都会检查条件,如果条件为真(返回值为 0),则执行循环体中的代码块;如果条件为假(返回值非 0),则退出循环。
while
语句的基本语法如下:
while [ condition ]
do
# 条件为真时执行的代码块
done
这里,[ condition ]
是条件表达式,用于评估循环是否应该继续执行。do
和 done
之间的代码块是循环体,只要条件为真,就会重复执行这段代码。
以下是一些 while
语句的使用示例:
示例 1:无限循环
#!/bin/bash
while true
do
echo "这是一个无限循环,按 Ctrl+C 退出."
sleep 1
done
这个脚本会无限循环打印一条消息,直到用户通过按下 Ctrl+C 组合键来中断脚本的执行。sleep 1
是用来防止消息过快地连续打印。
示例 2:计数循环
#!/bin/bash
counter=0
while [ $counter -lt 10 ]
do
echo "计数: $counter"
counter=$((counter + 1))
done
这个脚本使用一个计数器变量 counter
,在每次循环迭代时增加它的值,并打印当前的计数值,直到计数值达到 10 为止。
示例 3:读取用户输入直到特定值
#!/bin/bash
echo "请输入一个数字,输入 0 退出:"
while true
do
read -p "输入数字: " num
if [ "$num" -eq 0 ]; then
echo "你输入了 0,退出循环."
break
else
echo "你输入了 $num."
fi
done
这个脚本会不断提示用户输入一个数字,如果用户输入了 0,则打印一条消息并退出循环;否则,它会打印用户输入的数字并继续循环。
注意事项:
while
循环不会自动结束,除非在循环体内部有代码导致条件不再满足,或者使用了break
语句来退出循环。- 如果循环体中的代码没有改变循环条件的状态,将会导致无限循环,除非有外部因素(如用户中断)终止脚本的执行。
- 在条件表达式中,变量和操作符之间必须有空格,否则脚本可能会因为解析错误而失败。
五、Until循环
在 Shell 脚本中,until
循环与 while
循环非常相似,但它们的执行逻辑是相反的。until
循环会执行一段代码,直到指定的条件为真(返回值为 0)为止。换句话说,只要条件为假(返回值非 0),循环就会继续执行。一旦条件变为真,循环就会终止。
until
语句的基本语法如下:
until [ condition ]
do
# 条件为假时执行的代码块
done
这里的 [ condition ]
是条件表达式,只要它返回非零值(即条件为假),循环就会继续执行。一旦条件为真,until
循环就会终止。
下面是一些 until
循环的使用示例:
示例 1:用户输入检查
#!/bin/bash
echo "请输入一个非零数字,输入完成后按回车:"
until [ "$number" -ne 0 ]
do
read -p "你输入的数字是: " number
if ! [[ "$number" =~ ^[0-9]+$ ]]
then
echo "错误:请输入一个数字."
number=0 # 将 number 重置为 0 以确保循环继续
fi
done
echo "你输入了一个非零数字: $number"
在这个脚本中,until
循环会持续执行,直到用户输入一个非零数字为止。如果用户输入的不是数字,脚本会打印错误消息,并将 number
变量重置为 0,以确保循环继续。
示例 2:尝试连接到服务器
#!/bin/bash
server="example.com"
max_retries=5
retry_count=0
until ping -c 1 "$server" &> /dev/null
do
retry_count=$((retry_count + 1))
if [ $retry_count -ge $max_retries ]; then
echo "无法连接到服务器 $server,已达到最大重试次数."
exit 1
fi
echo "尝试连接到 $server...(第 $retry_count 次重试)"
sleep 5
done
echo "成功连接到服务器 $server."
在这个脚本中,until
循环会尝试 ping 服务器,直到成功为止。如果达到最大重试次数仍然无法连接,脚本会退出。否则,它会打印重试的消息,并等待 5 秒后再次尝试。
注意事项:
- 与
while
循环一样,until
循环不会自动结束,除非在循环体内部有代码导致条件变为真,或者使用了break
语句来退出循环。 - 如果循环体中的代码没有改变循环条件的状态,将会导致无限循环,除非有外部因素(如用户中断)终止脚本的执行。
- 确保在条件表达式中使用正确的逻辑,以避免出现逻辑错误或无限循环的情况。
until
循环在需要反复尝试某个操作直到满足特定条件时非常有用,特别是在处理网络连接、文件存在性检查等可能需要多次尝试的场景中。
六、Case 语句
在 Shell 脚本中,case
语句用于多分支条件测试。它允许脚本根据变量的值或表达式的结果来执行不同的代码块。case
语句在结构上类似于其他编程语言中的 switch
语句。
case
语句的基本语法如下:
case variable in
pattern1)
# 当 variable 匹配 pattern1 时执行的代码
;;
pattern2)
# 当 variable 匹配 pattern2 时执行的代码
;;
*)
# 当 variable 不匹配任何模式时执行的代码(默认情况)
;;
esac
这里,variable
是要测试的变量或表达式,pattern1
、pattern2
等是可能的匹配模式。每个模式后面跟着一对圆括号,其中包含当该模式匹配时要执行的代码。每个代码块的末尾使用 ;;
来表示该代码块的结束。*
是一个特殊的模式,表示匹配任何值(即默认情况)。
以下是一些 case
语句的使用示例:
示例 1:根据用户输入执行不同操作
#!/bin/bash
echo "请输入一个操作选项 (add, delete, list):"
read option
case $option in
add)
echo "执行添加操作"
;;
delete)
echo "执行删除操作"
;;
list)
echo "执行列表操作"
;;
*)
echo "未知的操作选项: $option"
;;
esac
在这个脚本中,用户被提示输入一个操作选项(add、delete 或 list)。然后,case
语句根据用户输入的值执行相应的代码块。
示例 2:根据文件扩展名执行不同操作
#!/bin/bash
file="example.txt"
extension="${file##*.}"
case $extension in
txt)
echo "处理文本文件"
;;
jpg|png)
echo "处理图片文件"
;;
pdf)
echo "处理 PDF 文件"
;;
*)
echo "未知的文件类型: $extension"
;;
esac
在这个脚本中,我们获取文件 example.txt
的扩展名,并使用 case
语句根据扩展名执行不同的操作。注意,我们可以使用 |
来指定多个模式,这些模式将被视为等价。
注意事项:
- 在
case
语句中,模式匹配是大小写敏感的,除非使用了特定的 shell 选项或工具(如[[ $variable == pattern ]]
)来进行不区分大小写的比较。 ;;
是用来分隔不同代码块的,每个代码块结束时都需要它。忘记添加;;
可能会导致不期望的行为,因为 shell 会继续执行下一个代码块直到遇到;;
或esac
。*
模式应该放在最后,作为默认情况处理所有不匹配其他模式的情况。
七、跳出循环break/continue
在 Shell 脚本中,如果你想要从循环中提前跳出,你可以使用 break
语句。break
语句会立即终止当前循环的执行,并继续执行循环之后的代码。
这里有一个简单的例子,演示了如何在 while
循环中使用 break
语句:
#!/bin/bash
counter=0
while true
do
echo "计数: $counter"
((counter++))
if [ $counter -eq 5 ]; then
echo "计数达到 5,跳出循环."
break
fi
done
echo "循环已结束."
在这个脚本中,我们有一个无限循环(while true
),它每次迭代都会打印当前的计数器值,并增加计数器的值。当计数器的值等于 5 时,if
语句的条件成立,break
语句被执行,从而跳出循环。之后,脚本会打印 “循环已结束.” 并结束执行。
同样地,你也可以在 until
循环中使用 break
语句来提前跳出循环。
#!/bin/bash
read -p "请输入一个数字 (输入 5 跳出): " number
until [ "$number" -eq 5 ]
do
echo "你输入了 $number."
read -p "请继续输入一个数字 (输入 5 跳出): " number
if [ "$number" -eq 5 ]; then
echo "你输入了 5,跳出循环."
break
fi
done
echo "循环已结束."
在这个脚本中,用户被提示输入一个数字,循环会持续进行直到用户输入 5 为止。一旦用户输入 5,if
语句的条件成立,break
语句被执行,从而跳出 until
循环。
需要注意的是,break
语句默认只跳出最内层的循环。如果你的脚本中有嵌套的循环,并且你想要从外层循环中跳出,你可能需要使用更复杂的逻辑或者考虑重新设计你的脚本结构。在某些情况下,使用函数和返回值可能是一个更好的选择。在 Shell 脚本中,如果你想要从循环中提前跳出,你可以使用 break
语句。break
语句会立即终止当前循环的执行,并继续执行循环之后的代码。
这里有一个简单的例子,演示了如何在 while
循环中使用 break
语句:
#!/bin/bash
counter=0
while true
do
echo "计数: $counter"
((counter++))
if [ $counter -eq 5 ]; then
echo "计数达到 5,跳出循环."
break
fi
done
echo "循环已结束."
在这个脚本中,我们有一个无限循环(while true
),它每次迭代都会打印当前的计数器值,并增加计数器的值。当计数器的值等于 5 时,if
语句的条件成立,break
语句被执行,从而跳出循环。之后,脚本会打印 “循环已结束.” 并结束执行。
同样地,你也可以在 until
循环中使用 break
语句来提前跳出循环。
#!/bin/bash
read -p "请输入一个数字 (输入 5 跳出): " number
until [ "$number" -eq 5 ]
do
echo "你输入了 $number."
read -p "请继续输入一个数字 (输入 5 跳出): " number
if [ "$number" -eq 5 ]; then
echo "你输入了 5,跳出循环."
break
fi
done
echo "循环已结束."
在这个脚本中,用户被提示输入一个数字,循环会持续进行直到用户输入 5 为止。一旦用户输入 5,if
语句的条件成立,break
语句被执行,从而跳出 until
循环。
break
语句默认只跳出最内层的循环。如果你的脚本中有嵌套的循环,并且你想要从外层循环中跳出,你可能需要使用更复杂的逻辑或者考虑重新设计你的脚本结构。
八、相关链接
- Linux官网
- Linux常用命令
- CentOS官网下载地址
- 「Linux系列」Linux简介及常见的Linux系统
- 「Linux系列」Linux 系统启动过程
- 「Linux系列」Linux 系统目录结构/忘记密码解决方法
- 「Linux系列」Linux 远程登录/文件基本属性
- 「Linux系列」Linux 文件与目录管理
- 「Linux系列」Linux 如何学习用户和用户组管理
- 「Linux系列」聊聊Linux磁盘管理的事
- 「Linux系列」聊聊vi/vim的3种命令模式
- 「Linux系列」了解下Linux yum(包管理工具)