声明! 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下,如涉及侵权马上删除文章,笔记只是方便各位师傅的学习和探讨,文章所提到的网站以及内容,只做学习交流,其他均与本人以及泷羽sec团队无关,切勿触碰法律底线,否则后果自负!!!!有兴趣的小伙伴可以点击下面连接进入b站主页[B站泷羽sec](https://space.bilibili.com/350329294)
在 Shell 编程中,until 循环是与 while 循环相反的一种循环结构。until 循环会在条件为 假 时执行循环体,直到条件变为 真 时停止循环。
until 循环的语法
until [ condition ]
do
# 循环体
done
- [ condition ]:是循环的判断条件,Shell 会在每次循环之前检查该条件。只要条件为假(返回非零值),循环就会继续执行。
- do 和 done:标记循环体的开始和结束。
until 循环的工作原理
- 在每次迭代之前,Shell 会检查条件是否为真(返回状态码为 0)。如果条件为 假(返回状态码非 0),则执行循环体内的代码。
- 当条件变为 真(返回状态码为 0)时,until 循环结束。
示例 1:基本的 until 循环
以下示例展示了如何使用 until 循环打印从 1 到 5 的数字:
#!/bin/bash
i=1
until [ $i -gt 5 ] # 条件是:i 小于或等于 5 时循环
do
echo $i
((i++)) # 自增 i 的值
done
解释:
- 变量 i 被初始化为 1。
- 循环的条件 [ $i -gt 5 ] 只有当 i 大于 5 时才为真,此时循环结束。
- 每次循环,echo $i 会打印当前的 i 值,然后通过 ((i++)) 将 i 增加 1。
输出:
示例 2:条件为假时继续执行
until 循环会一直执行,直到条件变为真。如果条件最初是 假,那么循环会立即开始执行。
#!/bin/bash
count=1
until [ $count -gt 10 ]
do
echo "Count is $count"
((count++)) # 自增 count
done
解释:
- 该循环会打印从 1 到 10 的值。
- 条件 [ $count -gt 10 ] 判断 count 是否大于 10,只有当 count 大于 10 时,循环才会结束。
- 循环体内,count 每次都会递增。
输出:
示例 3:使用 break 跳出循环
你可以使用 break 来提前终止 until 循环。
#!/bin/bash
count=1
until [ $count -gt 10 ]
do
if [ $count -eq 5 ]; then
echo "Reached 5, breaking out of loop"
break # 条件为 5 时跳出循环
fi
echo "Count is $count"
((count++))
done
解释:
- 当 count 等于 5 时,break 会终止循环。
- 其余部分正常打印 count 值。
输出:
示例 4:使用 continue 跳过当前循环
continue 用来跳过当前循环的剩余部分,直接进入下一次循环。
#!/bin/bash
count=1
until [ $count -gt 5 ]
do
((count++))
if [ $count -eq 3 ]; then
continue # 当count等于3时,跳过当前循环
fi
echo "Count is $count"
done
解释:
- 当 count 等于 3 时,continue 会跳过 echo 语句,直接进入下一次循环。
- 因此,3 不会被打印。
输出:
until 和 while 的对比
until 循环与 while 循环有相似之处,但它们的行为是相反的:
- while 循环:当条件为 真(返回状态码为 0)时继续执行。
- until 循环:当条件为 假(返回状态码非 0)时继续执行。
示例:相同功能的 until 和 while 循环
使用 while 循环:
#!/bin/bash
i=1
while [ $i -le 5 ]
do
echo $i
((i++))
done
使用 until 循环:
#!/bin/bash
i=1
until [ $i -gt 5 ]
do
echo $i
((i++))
done
这两个例子会产生相同的输出,因为它们都实现了相同的逻辑,只是条件判断的方式不同。
总结:
- until 循环会在条件为 假 时执行循环体,直到条件为 真 时结束。
- 可以结合 break 和 continue 控制循环的执行流程。
- until 循环和 while 循环的区别在于条件判断的逻辑:until 继续执行直到条件变为真,while 继续执行直到条件为假。
case ... esac
case ... esac 为多选择语句,与其他语言中的 switch ... case 语句类似,是一种多分支选择结构,每个 case 分支用右圆括号开始,用两个分号 ;; 表示 break,即执行结束,跳出整个 case ... esac 语句,esac(就是 case 反过来)作为结束标记。
可以用 case 语句匹配一个值与一个模式,如果匹配成功,执行相匹配的命令。
case ... esac 语法格式如下:
case 值 in
模式1)
command1
command2
...
commandN
;;
模式2)
command1
command2
...
commandN
;;
esac
case 工作方式如上所示,取值后面必须为单词 in,每一模式必须以右括号结束。取值可以为变量或常数,匹配发现取值符合某一模式后,其间所有命令开始执行直至 ;;。
取值将检测匹配的每一个模式。一旦模式匹配,则执行完匹配模式相应命令后不再继续其他模式。如果无一匹配模式,使用星号 * 捕获该值,再执行后面的命令。
下面的脚本提示输入 1 到 4,与每一种模式进行匹配:
echo '输入 1 到 4 之间的数字:'
echo '你输入的数字为:'
read aNum
case $aNum in
1) echo '你选择了 1'
;;
2) echo '你选择了 2'
;;
3) echo '你选择了 3'
;;
4) echo '你选择了 4'
;;
*) echo '你没有输入 1 到 4 之间的数字'
;;
esac
跳出循环
在循环过程中,有时候需要在未达到循环结束条件时强制跳出循环,Shell 使用两个命令来实现该功能:break 和 continue。
break 命令
break 命令允许跳出所有循环(终止执行后面的所有循环)。
下面的例子中,脚本进入死循环直至用户输入数字大于5。要跳出这个循环,返回到shell提示符下,需要使用break命令。
while :
do
echo -n "输入 1 到 5 之间的数字:"
read aNum
case $aNum in
1|2|3|4|5) echo "你输入的数字为 $aNum!"
;;
*) echo "你输入的数字不是 1 到 5 之间的! 游戏结束"
break
;;
esac
done
continue
continue 命令与 break 命令类似,只有一点差别,它不会跳出所有循环,仅仅跳出当前循环。对上面的例子进行修改:
#!/bin/bash
while :
do
echo -n "输入 1 到 5 之间的数字: "
read aNum
case $aNum in
1|2|3|4|5) echo "你输入的数字为 $aNum!"
;;
*) echo "你输入的数字不是 1 到 5 之间的!"
continue
echo "游戏结束"
;;
esac
done
shell编程函数
在 Shell 编程中,函数是一个非常重要的构造,它允许你将一组命令封装到一个可重复使用的代码块中,以便在脚本中多次调用。Shell 函数可以帮助你提高代码的可维护性和重用性。
1. 函数的基本语法
Shell 函数的基本语法如下:
[ function ] funname [()]
{
action;
[return int;]
}
或者:
function_name() {
# 函数体
}
- function_name 是函数的名称。
- 函数体是要执行的命令或语句。
2. 函数的定义与调用
示例 1:简单的函数定义与调用
#!/bin/bash
# 函数定义
greet() {
echo "Hello, $1!" # 使用传入的第一个参数
}
# 函数调用
greet "Alice"
greet "Bob"
解释:
- greet 函数接收一个参数,并打印一个问候语。$1 是传递给函数的第一个参数。
- greet "Alice" 会输出 Hello, Alice!,greet "Bob" 会输出 Hello, Bob!。
输出:
Hello, Alice!
Hello, Bob!
3. 函数中的参数
Shell 函数可以接收传递给它的参数。函数的参数由 $1、$2、$3 等表示,其中 $1 是第一个参数,$2 是第二个参数,依此类推。如果传入的参数超过 9 个,可以使用 ${10}、${11} 等来访问。
- $0:脚本本身的名字
- $1、$2、$3 等:传递给函数的第一个、第二个、第三个参数
- $#:传递给函数的参数个数
- $@:所有参数
- $*:所有参数(与 $@ 相似,但处理方式略有不同)
示例 2:带参数的函数
#!/bin/bash
# 函数定义
add_numbers() {
sum=$(( $1 + $2 )) # 将两个参数相加
echo "Sum: $sum"
}
# 函数调用
add_numbers 3 5
add_numbers 10 20
输出:
Sum: 8
Sum: 30
解释:
- add_numbers 函数接收两个参数,使用 (( )) 进行加法运算,并输出结果。
4. 返回值
Shell 函数可以通过 return 语句返回一个值,但是 return 语句只支持返回一个整数值(通常用于返回状态码),而不能直接返回字符串或浮动值。如果需要返回多个值或更复杂的数据类型,通常会通过 echo 或将值保存在全局变量中来实现。
示例 3:使用 return 返回状态码
#!/bin/bash
# 函数定义
check_even_odd() {
if (( $1 % 2 == 0 )); then
return 0 # 返回 0 表示偶数
else
return 1 # 返回 1 表示奇数
fi
}
# 函数调用
check_even_odd 4
if [ $? -eq 0 ]; then
echo "The number is even."
else
echo "The number is odd."
fi
check_even_odd 7
if [ $? -eq 0 ]; then
echo "The number is even."
else
echo "The number is odd."
fi
解释:
- check_even_odd 函数判断一个数字是偶数还是奇数。
- return 0 表示偶数,return 1 表示奇数。$? 可以获取上一个命令的返回值。
输出:
The number is even.
The number is odd.
示例 4:通过 echo 返回多个值
#!/bin/bash
# 函数定义
multiply_and_divide() {
product=$(( $1 * $2 ))
quotient=$(( $1 / $2 ))
echo $product $quotient # 通过 echo 返回多个值
}
# 函数调用
result=$(multiply_and_divide 6 3)
echo "Product and quotient: $result"
解释:
- multiply_and_divide 函数通过 echo 返回两个值(乘积和商)。
- 使用 $( ) 捕获函数的输出,将结果存储在 result 变量中。
输出:
Product and quotient: 18 2
5. 局部和全局变量
在 Shell 中,函数内部定义的变量是局部变量,默认情况下不会影响外部的变量。如果需要在函数外部访问或修改函数内的变量,通常使用 global 变量或通过 return 返回值。
示例 5:局部变量
#!/bin/bash
# 函数定义
increment() {
local num=$1 # 使用 local 定义局部变量
num=$(( num + 1 ))
echo "Incremented value: $num"
}
# 函数调用
result=$(increment 5)
echo "Result after increment: $result"
解释:
- local num=$1 在函数内部定义局部变量 num,确保该变量不会影响外部同名变量。
输出:
Incremented value: 6
Result after increment: 6
6. 函数递归
Shell 函数也支持递归,即函数在其内部调用自己。递归函数通常用来解决一些需要分解成相同子问题的问题。
示例 6:递归函数计算阶乘
#!/bin/bash
# 函数定义:递归计算阶乘
factorial() {
if [ $1 -le 1 ]; then
echo 1 # 基本条件
else
local result=$(( $1 * $(factorial $(( $1 - 1 )) ) )) # 递归调用
echo $result
fi
}
# 函数调用
result=$(factorial 5)
echo "Factorial of 5: $result"
解释:
- factorial 函数通过递归来计算阶乘。
- 基本条件是当输入为 1 时,返回 1,其他情况下返回 n * (n-1)!。
输出:
Factorial of 5: 120
7. 函数最佳实践
- 使用 local 关键字:局部变量可以防止函数修改全局变量,避免潜在的错误。
- 避免全局变量冲突:尽量避免在函数中使用全局变量,特别是当多个函数使用相同变量时。
- 合理使用递归:递归函数可以非常方便地解决问题,但需要小心避免栈溢出和确保基本条件存在。
总结
- 函数定义与调用: 使用 function_name() { } 来定义函数,通过 function_name 来调用。
- 参数: 可以通过 $1、$2 等方式访问传递给函数的参数。
- 返回值: 使用 return 返回状态码(整数),或者使用 echo 返回更复杂的值。
- 局部变量: 使用 local 关键字来定义局部变量。
- 递归: Shell 支持递归调用。