脚本解释器与变量

脚本文件类似

知道windows下有.bat脚本用来批量执行命令的,那Liunx下呢则是使用.sh脚本来批量执行命令,称为shell脚本

  1. 创建脚本的方式很多,只需要保证文件类型为.sh即可
touch 1.sh
```bash
touch 1.sh

Pasted-image-20241127005618

变量的概念

什么是变量?可以理解为一个盒子(a)里面存放的东西为盒子(变量)的值,在Liunx中的变量通常用美元($)搞提醒操作系统他是个变量

  • 如果设置全局变量只需要在设置变量的基础上前面加export
#尝试设置一个临时变量
box=v50
#然后用命令输出他,记得加上美元符号告诉系统他是一个变量
echo $box
```bash
#尝试设置一个临时变量
box=v50
#然后用命令输出他,记得加上美元符号告诉系统他是一个变量
echo $box

Pasted-image-20241127010759

引号的概念

单引号

  • 使用单引号包裹着变量则不会对变量进行解释(告诉他里面是什么)和赋值(将里面的东西输出)
#尝试设置一个变量
box=v50
#将变量用单引号括起来
echo '$box'
```bash
#尝试设置一个变量
box=v50
#将变量用单引号括起来
echo '$box'

Pasted-image-20241127013039

双引号

  • 双引号会对其中包含的变量进行解释或替换。默认不带符合则为双引号
#尝试设置一个变量
box=v50
#将变量用双引号括起来
echo "$box"
```bash
#尝试设置一个变量
box=v50
#将变量用双引号括起来
echo "$box"

Pasted-image-20241127013238

花括号

  • 花括号在变量主要中用于明确边界、条件检索、字符串替换和截取
#尝试设置一个变量
box=v50
#正常我们如果要和变量输出的内容进行贴合(字符wo)话需要空格,而可以使用花括号来明确边界
echo ${box}wo
```bash
#尝试设置一个变量
box=v50
#正常我们如果要和变量输出的内容进行贴合(字符wo)话需要空格,而可以使用花括号来明确边界
echo ${box}wo

Pasted-image-20241127015218

  • 条件检索(-为空使用默认值、+为空使用赋为默认值、+返回指定变量的值)
#尝试设置一个变量
box=
#输出一个值为空或者未定义的变量时,默认是无输出的,但是可以使用花括号来进行设置默认值
echo ${box:-v50}
```bash
#尝试设置一个变量
box=
#输出一个值为空或者未定义的变量时,默认是无输出的,但是可以使用花括号来进行设置默认值
echo ${box:-v50}

Pasted-image-20241127015531

脚本解释器

都知道Windows下的bat脚本的解释器是CMD,那么Liunx下的脚本解释器都有什么呢?默认情况下为/bin目录下的bashshdash

  • 具体选择那个都可以,也可以注意到sh的就解释器是软链接到dash
    Pasted-image-20241127021012
  1. 在脚本执行的开头指定解释器
#!/bin/bash

#尝试设置一个变量
box=v50
#输出
echo $box

```shell
#!/bin/bash

#尝试设置一个变量
box=v50
#输出
echo $box


系统变量和字符串

系统变量path

Liunx和windows系统中都有个全局系统变量名为path,里面存放了可执行文件的搜索路径,多个路径用 : 分隔。

  • 如果你想将脚本文件可以在系统的各个位置都可以执行话则需要将脚本的路径添加到path
  1. 临时添加
#还记得:$PATH表示保留原有的格式
export PATH="/root:$PATH"
```bash
#还记得:$PATH表示保留原有的格式
export PATH="/root:$PATH"

Pasted-image-20241127023941
2. 永久添加(在原本的基础上添加,或者将脚本移动到他变量的路经(不建议))

#这里的$PATH指引用他原本的变量,使用单引号是不解释他变量
echo 'export PATH="$PATH:/root"' >> ~/.bashrc
```bash
#这里的$PATH指引用他原本的变量,使用单引号是不解释他变量
echo 'export PATH="$PATH:/root"' >> ~/.bashrc

Pasted-image-20241127105714

字符串的概念

字符组成的有序序列的一种变量数据类型,用于表示文本数据。字符串可以包含字母、数字、空格、符号以及其他字符,例如标点符号、特殊符号等。

字符串的定义

  • 字符串可以受用单双引号或者无引号包裹,建议使用引号来避免歧义
#其实就是一种类型,只不过使用引号包裹,不仅限于设置变量为字符串,输出的内容也可以为字符串
str="v50"
#但是字符串和变量不是一个道理,输出的变量内容为字符串,但不能为理解为输出字符串
echo $str
```bash
#其实就是一种类型,只不过使用引号包裹,不仅限于设置变量为字符串,输出的内容也可以为字符串
str="v50"
#但是字符串和变量不是一个道理,输出的变量内容为字符串,但不能为理解为输出字符串
echo $str

Pasted-image-20241128020433

字符串的操作

  1. 输出多个字符串拼接
str="v50"
rts="kfc"
#为什么这里使用了花括号————避免引用变量产生歧义
echo ${rts}到了$str
```bash
str="v50"
rts="kfc"
#为什么这里使用了花括号————避免引用变量产生歧义
echo ${rts}到了$str

Pasted-image-20241128021040
2. 获取字符串长度

str="Linux"
# 输出:长度是:5
echo "长度是:${#str}"
```bash
str="Linux"
# 输出:长度是:5
echo "长度是:${#str}"

Pasted-image-20241128021254
3. 截取子字符串

str="Shell scripting is fun"
# 输出:scripting,从0开始数第六个截取到第九个
echo "${str:6:9}"
```bash
str="Shell scripting is fun"
# 输出:scripting,从0开始数第六个截取到第九个
echo "${str:6:9}"

Pasted-image-20241128021516
4. 查找和替换

str="I love Linux"
#在变量str里面找Liunx替换为Unix
echo "${str/Linux/Unix}"
```bash
str="I love Linux"
#在变量str里面找Liunx替换为Unix
echo "${str/Linux/Unix}"

Pasted-image-20241128021756

传参和数值运算

传参的基本概念

可以让脚本更加灵活地处理外部输入。通过位置参数来接收传递给脚本的参数。

位置参数

参数 含义
$0 脚本的名称
$1 传递给脚本的第1个参数
$2 传递给脚本的第2个参数
$3 传递给脚本的第3个参数
... 以此类推,表示传递给脚本的更多参数
$# 传递给脚本的参数总数
$@ 所有的参数,参数之间用空格分隔
$* 所有的参数,参数之间也用空格分隔(和$@ 类似,稍有区别)
"$@" 每个参数独立,逐行输出
"$*" 每个参数为一个整体,横向输出
$? 上一条命令的退出状态码
$$ 当前的运行进程ID

传参测试

#!/bin/bash

echo "脚本名称: $0"
echo "第一个参数: $1"
echo "第二个参数: $2"
echo "所有参数(\$@): $@"
echo "所有参数(\$*): $*"
echo "参数总数: $#"
echo "命令的退出状态:$?"
echo "命令的退出进程:$$"
```bash
#!/bin/bash

echo "脚本名称: $0"
echo "第一个参数: $1"
echo "第二个参数: $2"
echo "所有参数(\$@): $@"
echo "所有参数(\$*): $*"
echo "参数总数: $#"
echo "命令的退出状态:$?"
echo "命令的退出进程:$$"

Pasted-image-20241128024610

数值运算

变量的算数运算

  1. 使用$(( ))进行一个简单的运算,例子使用变量进行,实际上能直接套数值
#!/bin/bash

a=8
b=9

# 加法
sum=$((a + b))
echo "加法:$a + $b = $sum"

# 减法
diff=$((a - b))
echo "减法:$a - $b = $diff"

# 乘法
product=$((a * b))
echo "乘法:$a * $b = $product"

# 除法
quotient=$((a / b))
echo "除法:$a / $b = $quotient"

# 取余
remainder=$((a % b))
echo "取余:$a % $b = $remainder"

```bash
#!/bin/bash

a=8
b=9

# 加法
sum=$((a + b))
echo "加法:$a + $b = $sum"

# 减法
diff=$((a - b))
echo "减法:$a - $b = $diff"

# 乘法
product=$((a * b))
echo "乘法:$a * $b = $product"

# 除法
quotient=$((a / b))
echo "除法:$a / $b = $quotient"

# 取余
remainder=$((a % b))
echo "取余:$a % $b = $remainder"


Pasted-image-20241128025710

  1. 使用 expr 进行算术运算,例子使用变量进行,实际上能直接套数值
    • 运算需要使用空格,且需要对运算符进行转义。
#!/bin/bash

a=5
b=3

# 加法
sum=$(expr $a + $b)
echo "加法:$a + $b = $sum"

# 减法
diff=$(expr $a - $b)
echo "减法:$a - $b = $diff"

# 乘法(*为通配符,需要使用反斜杠转义)
product=$(expr $a \* $b)
echo "乘法:$a * $b = $product"

# 除法
quotient=$(expr $a / $b)
echo "除法:$a / $b = $quotient"

# 取余
remainder=$(expr $a % $b)
echo "取余:$a % $b = $remainder"

```bash
#!/bin/bash

a=5
b=3

# 加法
sum=$(expr $a + $b)
echo "加法:$a + $b = $sum"

# 减法
diff=$(expr $a - $b)
echo "减法:$a - $b = $diff"

# 乘法(*为通配符,需要使用反斜杠转义)
product=$(expr $a \* $b)
echo "乘法:$a * $b = $product"

# 除法
quotient=$(expr $a / $b)
echo "除法:$a / $b = $quotient"

# 取余
remainder=$(expr $a % $b)
echo "取余:$a % $b = $remainder"


Pasted-image-20241128030401

扩展运算

  • shell计算中默认只能整数,可配合bc来进行浮点运算语法:echo "表达式" | bc
#!/bin/bash

# 浮动点数除法,scale为设置小数点后几位
result=$(echo "scale=2; 5 / 2" | bc)
echo "浮动点数除法:5 / 5 = $result"

```bash
#!/bin/bash

# 浮动点数除法,scale为设置小数点后几位
result=$(echo "scale=2; 5 / 2" | bc)
echo "浮动点数除法:5 / 5 = $result"


Pasted-image-20241128030654

  • 配合bc-l数学库参数来进行得出算数平方根sqrt、正弦s、余弦c、反正弦a、对数l、次方e、正切j、反余弦f、反正切p、x^y次方x^y、圆周率PI
#!/bin/bash
# 浮动点数除法,scale为设置小数点后几位,sqrt为计算平方根
result=$(echo "scale=2;sqrt(64)"| bc -l)
echo "64的算数平方根为$result"
```bash
#!/bin/bash
# 浮动点数除法,scale为设置小数点后几位,sqrt为计算平方根
result=$(echo "scale=2;sqrt(64)"| bc -l)
echo "64的算数平方根为$result"

Pasted-image-20241128031235

  • 配合bc-q参数运算后不显示提示符,即运算后不弹窗
echo "scale=2; 5/7" | bc -q
```bash
echo "scale=2; 5/7" | bc -q

用户交互与关系运算符

用户交互

意味可以过脚本与用户进行输入和输出的交互。通过提示用户输入信息,并根据用户输入执行相应的操作。

基本交互

  • 通过read命令来获取用户输入的参数,如读取多个变量则需要使用空格来分隔
#!/bin/bash
echo "请输入你的名字和年龄:"
#依次将输入的内容赋值给变量
read name age
echo "你的名字是:$name,年龄是:$age"
```bash
#!/bin/bash
echo "请输入你的名字和年龄:"
#依次将输入的内容赋值给变量
read name age
echo "你的名字是:$name,年龄是:$age"

Pasted-image-20241128033911

提示交互

  • 通过read命令来获取用户输入的参数-p来提供输入前的提示信息
#!/bin/bash
read -p "请输入你的名字:" name
read -p "请输入你的年龄:" age

echo "你的名字是:$name,年龄是:$age"
```bash
#!/bin/bash
read -p "请输入你的名字:" name
read -p "请输入你的年龄:" age

echo "你的名字是:$name,年龄是:$age"

Pasted-image-20241128034215

read全部参数

不同参数之间可以配合使用,例如设置隐藏输入内容和提示信息可以使用-ps

参数 说明
-p 提示用户输入,后面跟提示信息。
-s 隐藏输入内容(常用于输入密码)。
-t 设置超时,单位为秒,超时后返回非零值。
-i 设置默认值,如果用户没有输入,则使用默认值。
-r 不处理反斜杠(\)转义字符,输入会原样保存。
-a 将输入保存为数组,按空格或换行分割。
-n 读取指定的字符数,限制用户输入的字符长度。

菜单交互

  • 基本语法
select variable in option1 option2 option3 ...; do
# 对应的操作
done
```bash
select variable in option1 option2 option3 ...; do
# 对应的操作
done

  • 简单的操作,无退出操作只能通过ctrl+c退出
#!/bin/bash

# 显示菜单
echo "你要吃什么"
select option in "白米饭" "红米饭" "叉烧饭";
do
echo "你选择了$option"
done
```bash
#!/bin/bash

# 显示菜单
echo "你要吃什么"
select option in "白米饭" "红米饭" "叉烧饭";
do
echo "你选择了$option"
done

Pasted-image-20241128035659

关系逻辑运算

关系运算符

用于比较两个整数值的大小和相等关系。

运算符 说明 示例
-eq 等于(equal) a -eq b:a 等于 b
-ne 不等于(not equal) a -ne b:a 不等于 b
-gt 大于(greater than) a -gt b:a 大于 b
-lt 小于(less than) a -lt b:a 小于 b
-ge 大于或等于(greater than or equal) a -ge b:a 大于或等于 b
-le 小于或等于(less than or equal) a -le b:a 小于或等于 b

if条件控制语句

  • 还可配合逻辑与关系运算
  • [ condition ] 之间一定要有空格,条件和操作符两边都需要空格。
if [ condition ]; then
# 条件成立时执行的命令
elif [ another_condition ]; then
# 如果第一个条件不成立,且第二个条件成立时执行的命令
else
# 如果上述所有条件都不成立时执行的命令
fi

```bash
if [ condition ]; then
# 条件成立时执行的命令
elif [ another_condition ]; then
# 如果第一个条件不成立,且第二个条件成立时执行的命令
else
# 如果上述所有条件都不成立时执行的命令
fi


实例

  • []可以删掉,在if前面空格间隔使用test也一样可以输出,但不推荐使用
#!/bin/bash
a=10
b=20
#判断a是否小于b,为真则输出,假则跳出输出
if [ $a -lt $b ]; then
echo "a 小于 b"
fi
```bash
#!/bin/bash
a=10
b=20
#判断a是否小于b,为真则输出,假则跳出输出
if [ $a -lt $b ]; then
echo "a 小于 b"
fi

Pasted-image-20241128041259

  • 配合菜单使用
#!/bin/bash
echo "你要吃什么"
select option in "白米饭" "红米饭" "叉烧饭"; do
if [ "$option" = "白米饭" ]; then
echo "白白的$option好吃吗?"
elif [ "$option" = "红米饭" ]; then
echo "红红的$option好吃吗?"
elif [ "$option" = "叉烧饭" ]; then
echo "$option我最爱吃!"
else
echo "请你吃大嘴巴子"
break # 退出 select 循环
fi
done

```bash
#!/bin/bash
echo "你要吃什么"
select option in "白米饭" "红米饭" "叉烧饭"; do
if [ "$option" = "白米饭" ]; then
echo "白白的$option好吃吗?"
elif [ "$option" = "红米饭" ]; then
echo "红红的$option好吃吗?"
elif [ "$option" = "叉烧饭" ]; then
echo "$option我最爱吃!"
else
echo "请你吃大嘴巴子"
break # 退出 select 循环
fi
done


Pasted-image-20241128044351

字符运算符与逻辑运算符

字符运算符:

运算符 说明 示例
= 判断两个字符串是否相等 if [ "$str1" = "$str2" ]; then
!= 判断两个字符串是否不相等 if [ "$str1" != "$str2" ]; then
-z 判断字符串是否为空 if [ -z "$str" ]; then
-n 判断字符串是否非空 if [ -n "$str" ]; then
< 判断字符串是否按字典顺序小于另一个字符串(仅支持字符比较) if [[ "$str1" < "$str2" ]]; then
> 判断字符串是否按字典顺序大于另一个字符串(仅支持字符比较) if [[ "$str1" > "$str2" ]]; then
== 判断两个字符串是否相等(适用于[[ ]] 中) if [[ "$str1" == "$str2" ]]; then

实例

  1. 判断相等
#!/bin/bash
str1="hallo"
str2="Hallo"

if [ $str1 = $str2 ]; then
echo "相等"
else
echo"不相等"
fi
```bash
#!/bin/bash
str1="hallo"
str2="Hallo"

if [ $str1 = $str2 ]; then
echo "相等"
else
echo"不相等"
fi

Pasted-image-20241128045507

  • 为空判断
#!/bin/bash
str1="hallo"

if [ -n $str1 ]; then
echo "不为空"
else
echo"空"
fi
```bash
#!/bin/bash
str1="hallo"

if [ -n $str1 ]; then
echo "不为空"
else
echo"空"
fi

Pasted-image-20241128045803

逻辑运算符

运算符 说明 旧语法(不推荐) 现代语法(推荐) 示例
逻辑“与” 只有两个条件都为真时,整体为真 -a && [ condition1 -a condition2 ][ condition1 ] && [ condition2 ]
逻辑“或” 至少一个条件为真时,整体为真 -o `
逻辑“非” 取反条件,条件为真时变假 ! ! [ ! condition ]

实例

  • 逻辑与运算
#!/bin/bash

x=5
y=8

# 旧语法 - 使用 -a
if [ "$x" -gt 3 -a "$y" -lt 10 ]; then
echo "x 大于 3 且 y 小于 10"
else
echo "条件不成立"
fi

# 现代语法 - 使用 &&
if [ "$x" -gt 3 ] && [ "$y" -lt 10 ]; then
echo "x 大于 3 且 y 小于 10"
else
echo "条件不成立"
fi

```bash
#!/bin/bash

x=5
y=8

# 旧语法 - 使用 -a
if [ "$x" -gt 3 -a "$y" -lt 10 ]; then
echo "x 大于 3 且 y 小于 10"
else
echo "条件不成立"
fi

# 现代语法 - 使用 &&
if [ "$x" -gt 3 ] && [ "$y" -lt 10 ]; then
echo "x 大于 3 且 y 小于 10"
else
echo "条件不成立"
fi


Pasted-image-20241128051119

for循环与while循环

for循环

基本语法

  • variable:表示当前循环中的变量,它将依次取 list 中的每个值。
  • list:可以是一个列表,或者是通过命令生成的输出结果。
for variable in list
do #开始
# 执行的命令
done #结束

```bash
for variable in list
do #开始
# 执行的命令
done #结束


遍历固定元素列表

  • 方法一(不设变量)
#!/bin/bash
for tian in "一" "二" "三" "四" "五" "六" "日"
do
echo "今天星期$tian"
done
```bash
#!/bin/bash
for tian in "一" "二" "三" "四" "五" "六" "日"
do
echo "今天星期$tian"
done

Pasted-image-20241129011022

  • 方法二(设置变量)
#!/bin/bash

# 定义一个数组
fruits=("一" "二" "三" "四" "五" "六" "日")

# ${fruits[@]}使用 for 循环遍历数组
for fruit in "${fruits[@]}"
do
echo "今天星期$fruit"
done

```bash
#!/bin/bash

# 定义一个数组
fruits=("一" "二" "三" "四" "五" "六" "日")

# ${fruits[@]}使用 for 循环遍历数组
for fruit in "${fruits[@]}"
do
echo "今天星期$fruit"
done


Pasted-image-20241129011650

遍历数字范围

  • 方法一(不设置变量)
#!/bin/bash

# 遍历数字范围 1 到 10 间隔为2(可以不要)
for i in {1..10..2}
do
echo "数字是 $i"
done

```bash
#!/bin/bash

# 遍历数字范围 1 到 10 间隔为2(可以不要)
for i in {1..10..2}
do
echo "数字是 $i"
done


Pasted-image-20241129011844

  • 方法二(通过seq生成):seq [起始值] [间隔] [结束值]
#!/bin/bash

# 使用 seq 生成数字 1 到 10,间隔为 2
for i in $(seq 1 2 10)
do
echo "数字是 $i"
done

```bash
#!/bin/bash

# 使用 seq 生成数字 1 到 10,间隔为 2
for i in $(seq 1 2 10)
do
echo "数字是 $i"
done


Pasted-image-20241129011844

遍历命令

  • for循环和Liunx下的命令配合操作,使用命令的输出的当作字符串返回——$()
#!/bin/bash
data=$(date)

echo "日期:$data"
```bash
#!/bin/bash
data=$(date)

echo "日期:$data"

Pasted-image-20241129013230

  • 配合for循环使用获取
#!/bin/bash

# 使用 find 查找所有 .txt 文件,并通过 for 循环处理
for txt_file in $(find /etc -name "*.txt")
do
# 输出当前正在处理的文件
echo "正在查看文件:$txt_file"

# 打开文件内容并输出
cat "$txt_file"
echo "====================" # 分隔符
done
```bash
#!/bin/bash

# 使用 find 查找所有 .txt 文件,并通过 for 循环处理
for txt_file in $(find /etc -name "*.txt")
do
# 输出当前正在处理的文件
echo "正在查看文件:$txt_file"

# 打开文件内容并输出
cat "$txt_file"
echo "====================" # 分隔符
done

Pasted-image-20241129014738

(())配合类似C风格

  • (())里面可以进行简单的算数运算和条件运算,另外的let命令也可以进行算数运算
简单语法
for ((初始值; 条件; 自变量)) #自变量的值可为: i++ i-- i+=2(每次加2)
do
# 代码块
done

```bash
for ((初始值; 条件; 自变量)) #自变量的值可为: i++ i-- i+=2(每次加2)
do
# 代码块
done


实例
  • 从1到100
#!/bin/bash
#i初始值为1,当i小于或等于100时就do一次,然后i自增
for ((i=1;i<=100;i++))
do
echo "$i"
done
```bash
#!/bin/bash
#i初始值为1,当i小于或等于100时就do一次,然后i自增
for ((i=1;i<=100;i++))
do
echo "$i"
done

Pasted-image-20241129020245

while循环

基础语法

#直到条件不成立(假)时停止运行,或者使用循环终止
while [ 条件 ]
do
# 需要重复执行的命令
done

```bash
#直到条件不成立(假)时停止运行,或者使用循环终止
while [ 条件 ]
do
# 需要重复执行的命令
done


循环输出数字

#!/bin/bash

i=1
while [ $i -el 5 ]
do
echo "i = $i"
((i++)) # 自增 i
done

```bash
#!/bin/bash

i=1
while [ $i -el 5 ]
do
echo "i = $i"
((i++)) # 自增 i
done


Pasted-image-20241129021119

终止语句配合使用

  • break终止当前循环
#!/bin/bash

i=0
while true #设置永为真
do
echo "当前值:$i"
if [ $i -eq 12 ]; then #内嵌条件判断
echo "i 等于 5,终止循环"
break # 当 i 等于 5 时终止循环
fi
let i+=2 #上方条件不符合进行运算
done
echo "跳出while循环"
```bash
#!/bin/bash

i=0
while true #设置永为真
do
echo "当前值:$i"
if [ $i -eq 12 ]; then #内嵌条件判断
echo "i 等于 5,终止循环"
break # 当 i 等于 5 时终止循环
fi
let i+=2 #上方条件不符合进行运算
done
echo "跳出while循环"

Pasted-image-20241129022741

  • continue跳出本次循环,并回到循环。
#!/bin/bash

i=1
while [ $i -le 50 ] #小于50则循环
do
if [ $((i % 5)) -eq 0 ]; then #i除5的余等于0时执行一次
echo "$i为5的倍数"
((i++))
continue # 跳出本次循环(while后面语句都的都不执行了,重新再执行一次while)
fi
echo "当前值为:$i"
((i++))
done
```bash
#!/bin/bash

i=1
while [ $i -le 50 ] #小于50则循环
do
if [ $((i % 5)) -eq 0 ]; then #i除5的余等于0时执行一次
echo "$i为5的倍数"
((i++))
continue # 跳出本次循环(while后面语句都的都不执行了,重新再执行一次while)
fi
echo "当前值为:$i"
((i++))
done

Pasted-image-20241129023734

配合|管道符使用

#!/bin/bash

cat /etc/apt/sources.list | while read line #read逐行读取cat输出的内容
do
let i++
echo "第$i行:$line"
done

```bash
#!/bin/bash

cat /etc/apt/sources.list | while read line #read逐行读取cat输出的内容
do
let i++
echo "第$i行:$line"
done


Pasted-image-20241129024458

until循环与case判断

until循环

基本语法

until [ condition ]
do
# commands当条件不成立才退出
done

```bash
until [ condition ]
do
# commands当条件不成立才退出
done


数值累加

#!/bin/bash

sum=0 i=1
until [ $i -gt 10 ] #知道满足条件退出循环
do
sum=$((sum + i))
let 1++
done

echo "1 到 10 的和是:$sum"

```bash
#!/bin/bash

sum=0 i=1
until [ $i -gt 10 ] #知道满足条件退出循环
do
sum=$((sum + i))
let 1++
done

echo "1 到 10 的和是:$sum"


Pasted-image-20241129031005

case判断

基本语法

case $variable in
pattern1)
# 处理匹配到 pattern1 的情况
;;
pattern2)
# 处理匹配到 pattern2 的情况
;;
*)
# 默认情况下执行的代码
;;
esac
```bash
case $variable in
pattern1)
# 处理匹配到 pattern1 的情况
;;
pattern2)
# 处理匹配到 pattern2 的情况
;;
*)
# 默认情况下执行的代码
;;
esac

根据输入执行相应操作

#!/bin/bash

# 显示菜单
echo "需要执行的操作"
select option in "安装" "修复" "卸载";
do
case $option in
安装)
echo "正在安装中..."
sleep 2 #等待两秒
break
;;
修复)
echo "正在修复中..."
sleep 2 #等待两秒
break
;;
卸载)
echo "正在卸载中..."
sleep 10 #等待10秒
break
;;
*)
echo "已退出操作"
exit #关闭脚本
;;
esac
done
```bash
#!/bin/bash

# 显示菜单
echo "需要执行的操作"
select option in "安装" "修复" "卸载";
do
case $option in
安装)
echo "正在安装中..."
sleep 2 #等待两秒
break
;;
修复)
echo "正在修复中..."
sleep 2 #等待两秒
break
;;
卸载)
echo "正在卸载中..."
sleep 10 #等待10秒
break
;;
*)
echo "已退出操作"
exit #关闭脚本
;;
esac
done

Pasted-image-20241129032115

封装函数与脚本调用与重定向

封装函数

函数封装就是指将一段可重用的代码放入一个函数中,并通过函数的参数和返回值来与外部的代码进行交互。

基本语法

传参变量回看

  • 封装方法一
function_name() { #封装函数
# commands
}

function_name(传递的参数) #调用
```bash
function_name() { #封装函数
# commands
}

function_name(传递的参数) #调用

  • 封装方法二
function function_name { #封装函数
# commands
}

function_name(传递的参数) #调用
```bash
function function_name { #封装函数
# commands
}

function_name(传递的参数) #调用

实例

  1. 日志打印
#!/bin/bash

# 定义日志打印函数
log_message() {
#local定义局部变量
local log_level=$1 #参1
local message=$2 #参二
echo "[$log_level] $(date): $message"
}

# 调用日志函数
log_message "INFO" "脚本开始执行"
log_message "ERROR" "文件未找到"
log_message "DEBUG" "正在调试模式"

```bash
#!/bin/bash

# 定义日志打印函数
log_message() {
#local定义局部变量
local log_level=$1 #参1
local message=$2 #参二
echo "[$log_level] $(date): $message"
}

# 调用日志函数
log_message "INFO" "脚本开始执行"
log_message "ERROR" "文件未找到"
log_message "DEBUG" "正在调试模式"


Pasted-image-20241129034745
2. 备份文件脚本

#!/bin/bash

# 定义备份函数
backup_file() {
local source_file=$1
local backup_file=$2

if [ ! -f "$source_file" ]; then
echo "错误:源文件 $source_file 不存在"
return 1
fi
# 执行备份
cp "$source_file" "$backup_file"
echo "文件已成功备份:$source_file$backup_file"
}
read -p "要备份的文件:" file
read -p "备份的路径:" dir
# 调用备份函数
backup_file "$file" "$dir"

```bash
#!/bin/bash

# 定义备份函数
backup_file() {
local source_file=$1
local backup_file=$2

if [ ! -f "$source_file" ]; then
echo "错误:源文件 $source_file 不存在"
return 1
fi
# 执行备份
cp "$source_file" "$backup_file"
echo "文件已成功备份:$source_file$backup_file"
}
read -p "要备份的文件:" file
read -p "备份的路径:" dir
# 调用备份函数
backup_file "$file" "$dir"


Pasted-image-20241129040203

脚本调用

  1. 用一个脚本调用另一个脚本的输出结果
#!/bin/bash

# 显示菜单
echo "需要执行的操作"
select option in "安装" "卸载";
do
case $option in
安装)
./2.sh #.会新的子 Shell 中执行目标脚本,变量会与当前脚本不冲突
break
;;
卸载)
source 3.sh #source会加载另一个脚本文件的内容并在当前 Shell 中执行,变量可复用
break
;;
*)
echo "已退出操作"
exit #关闭脚本
;;
esac
done

```bash
#!/bin/bash

# 显示菜单
echo "需要执行的操作"
select option in "安装" "卸载";
do
case $option in
安装)
./2.sh #.会新的子 Shell 中执行目标脚本,变量会与当前脚本不冲突
break
;;
卸载)
source 3.sh #source会加载另一个脚本文件的内容并在当前 Shell 中执行,变量可复用
break
;;
*)
echo "已退出操作"
exit #关闭脚本
;;
esac
done


Pasted-image-20241129042244
2. 从另一个脚本中定义变量执行当前脚本

#!/bin/bash

# 显示菜单
echo "需要执行的操作"
select option in "安装" "卸载";
do
case $option in
安装)
./2.sh #.会新的子 Shell 中执行目标脚本,变量会与当前脚本不冲突
echo $test
break
;;
卸载)
source 3.sh #source会加载另一个脚本文件的内容并在当前 Shell 中执行,变量可复用
echo $test
break
;;
*)
echo "已退出操作"
exit #关闭脚本
;;
esac
done

```bash
#!/bin/bash

# 显示菜单
echo "需要执行的操作"
select option in "安装" "卸载";
do
case $option in
安装)
./2.sh #.会新的子 Shell 中执行目标脚本,变量会与当前脚本不冲突
echo $test
break
;;
卸载)
source 3.sh #source会加载另一个脚本文件的内容并在当前 Shell 中执行,变量可复用
echo $test
break
;;
*)
echo "已退出操作"
exit #关闭脚本
;;
esac
done


Pasted-image-20241129043159

重定向操作

重定向操作符

流名称 文件描述符 描述 示例
标准输入(stdin) 0 用于输入数据,通常从键盘或文件中读取数据 cat < input.txt
标准输出(stdout) 1 用于输出程序的正常结果,通常输出到终端屏幕或文件 echo "Hello, World!" > output.txt
标准错误(stderr) 2 用于输出程序的错误信息,通常输出到终端屏幕,专门处理错误信息 ls nonexistent_file 2> error.log
  1. 标准输入(将文本的内容当作命令的执行变量)
ls -l < 3.txt
```bash
ls -l < 3.txt

Pasted-image-20241129043321

  1. 标准输出(将命令执行的输出重定向到文件里面)
ls > z.txt
```bash
ls > z.txt

Pasted-image-20241129043321
3. 标准错误(命令执行失败将报错重定向到文件内)

nmap 2> 1.txt
```bash
nmap 2> 1.txt

Pasted-image-20241129045350
4. 组合使用

ls > 2.txt 2>1.txt

nmap > 2.txt 2>1.txt
```bash
ls > 2.txt 2>1.txt

nmap > 2.txt 2>1.txt

Pasted-image-20241129045702

文件运算符

1. 文件存在性和类型测试运算符

运算符 含义 示例
-e FILE 测试文件是否存在。 [ -e /path/to/file ] # 如果文件存在则返回 true
-f FILE 测试文件是否是常规文件。 [ -f /path/to/file ] # 如果是常规文件则返回 true
-d FILE 测试文件是否是目录。 [ -d /path/to/dir ] # 如果是目录则返回 true
-s FILE 测试文件是否非空(文件大小大于 0 字节)。 [ -s /path/to/file ] # 如果文件非空则返回 true
-L FILE 测试文件是否是符号链接。 [ -L /path/to/file ] # 如果是符号链接则返回 true
-h FILE 测试文件是否是符号链接(-L-h 功能相同)。 [ -h /path/to/file ] # 如果是符号链接则返回 true
-p FILE 测试文件是否是有名管道(FIFO)。 [ -p /path/to/file ] # 如果是有名管道则返回 true
-c FILE 测试文件是否是字符设备文件(比如终端)。 [ -c /path/to/file ] # 如果是字符设备文件则返回 true
-b FILE 测试文件是否是块设备文件(比如硬盘设备)。 [ -b /path/to/file ] # 如果是块设备文件则返回 true
-w FILE 测试文件是否可写。 [ -w /path/to/file ] # 如果可写则返回 true
-r FILE 测试文件是否可读。 [ -r /path/to/file ] # 如果可读则返回 true
-x FILE 测试文件是否可执行。 [ -x /path/to/file ] # 如果可执行则返回 true
-u FILE 测试文件是否设置了 SUID 位。 [ -u /path/to/file ] # 如果设置了 SUID 位则返回 true
-g FILE 测试文件是否设置了 SGID 位。 [ -g /path/to/file ] # 如果设置了 SGID 位则返回 true
-k FILE 测试文件是否设置了粘着位(sticky bit)。 [ -k /path/to/file ] # 如果设置了粘着位则返回 true
-O FILE 测试文件是否归当前用户所有。 [ -O /path/to/file ] # 如果当前用户是文件的所有者则返回 true
-G FILE 测试文件是否归当前用户组所有。 [ -G /path/to/file ] # 如果当前用户组是文件的组则返回 true
-N FILE 测试文件是否自上次访问以来被修改过。 [ -N /path/to/file ] # 如果文件自上次访问以来被修改过则返回 true

2. 文件比较运算符

除了用于文件属性的测试外,还有一些文件比较运算符,用于比较两个文件的内容或属性。

运算符 含义 示例
FILE1 -nt FILE2 测试 FILE1 是否比 FILE2 新(文件修改时间)。 [ /path/to/file1 -nt /path/to/file2 ] # 如果 file1 比 file2 新则返回 true
FILE1 -ot FILE2 测试 FILE1 是否比 FILE2 旧(文件修改时间)。 [ /path/to/file1 -ot /path/to/file2 ] # 如果 file1 比 file2 旧则返回 true
FILE1 -ef FILE2 测试 FILE1 和 FILE2 是否是相同的文件(硬链接)。 [ /path/to/file1 -ef /path/to/file2 ] # 如果 file1 和 file2 是同一文件(硬链接)则返回 true

综合实例

简单的运算

#!/bin/bash

read -p "输入操作数一:" num1
read -p "输入操作数二:" num2
read -p "输入操作符:" opt

if [ "$num1" -eq 0 ] && [ "$num2" -eq 0 ]; then
    echo "操作数不能为0"
else
    case $opt in
    "+")
        echo "结果为:$((num1 + num2))"
        ;;
    "-")
        echo "结果为:$((num1 - num2))"
        ;;
    "*")
        echo "结果为:$((num1 * num2))"
        ;;
    "/")
        echo "结果为:$((num1 / num2)).$(expr $num1 % $num2)"
        ;;
    *)
        echo "符号错误"
        ;;
    esac
fi
```bash
#!/bin/bash

read -p "输入操作数一:" num1
read -p "输入操作数二:" num2
read -p "输入操作符:" opt

if [ "$num1" -eq 0 ] && [ "$num2" -eq 0 ]; then
    echo "操作数不能为0"
else
    case $opt in
    "+")
        echo "结果为:$((num1 + num2))"
        ;;
    "-")
        echo "结果为:$((num1 - num2))"
        ;;
    "*")
        echo "结果为:$((num1 * num2))"
        ;;
    "/")
        echo "结果为:$((num1 / num2)).$(expr $num1 % $num2)"
        ;;
    *)
        echo "符号错误"
        ;;
    esac
fi

Pasted-image-20241129142425

阶乘运算

nx () {
    local num=$1
    # 获取传入的参数
    local result=1
    # 初始化结果为 1
    for((i=1;i<=num;i++))
    do
        result=$(($result * i))
        # 使用 result 变量存储结果
    done
    echo !${num}的的阶乘为:$result # 打印结果
}

read -p "请输入一个数来求出他的阶乘:" n
if [ $n -gt 0 ]; then
    nx $n # 调用函数
else
    echo "输入的数必须大于0"
fi
```bash
nx () {
    local num=$1
    # 获取传入的参数
    local result=1
    # 初始化结果为 1
    for((i=1;i<=num;i++))
    do
        result=$(($result * i))
        # 使用 result 变量存储结果
    done
    echo !${num}的的阶乘为:$result # 打印结果
}

read -p "请输入一个数来求出他的阶乘:" n
if [ $n -gt 0 ]; then
    nx $n # 调用函数
else
    echo "输入的数必须大于0"
fi

Pasted-image-20241129163352

获取指定网络的IPv4地址

  1. 尝试在Liunx下用命令获取
ip addr show eth0 | grep "/24" | awk '{print $2}' | cut -d'/' -f1
#查看网络指定接口eth0 |筛选出/24的行|获取第二个字段内容|以/为字段分隔符号,获取第一个字段的内容
```bash
ip addr show eth0 | grep "/24" | awk '{print $2}' | cut -d'/' -f1
#查看网络指定接口eth0 |筛选出/24的行|获取第二个字段内容|以/为字段分隔符号,获取第一个字段的内容

Pasted-image-20241129170446
2. 知道Liunx中负责定时任务的的cron,尝试添加

crontab -l 
#查看当前用户的定时任务

echo "* * * * * echo 'test'" | crontab -
#crontab - 可以配合管道副将输出的内容添加进去

* * * * * *执行命令 #定时格式
- - - - - -
| | | | | +----指定的用户
| | | | +---- 星期几 (0 - 7) (Sunday = 0 or 7)
| | | +------ 月份 (1 - 12)
| | +-------- 日期 (1 - 31)
| +---------- 小时 (0 - 23)
+------------ 分钟 (0 - 59)

```bash
crontab -l
#查看当前用户的定时任务

echo "* * * * * echo 'test'" | crontab -
#crontab - 可以配合管道副将输出的内容添加进去

* * * * * *执行命令 #定时格式
- - - - - -
| | | | | +----指定的用户
| | | | +---- 星期几 (0 - 7) (Sunday = 0 or 7)
| | | +------ 月份 (1 - 12)
| | +-------- 日期 (1 - 31)
| +---------- 小时 (0 - 23)
+------------ 分钟 (0 - 59)


Pasted-image-20241130162706

  • 编写脚本
#!/bin/bash

# 定义函数
ip4() {
local da=$(date)
local ta=$(ip addr show eth0 | grep "/24" | awk '{print $2}' | cut -d'/' -f1)
echo "$da 当前IP地址为:$ta" >> /tmp/ip.txt
}

# 获取脚本的绝对路径
path="$(realpath "$0")"
time="* 6 * * * $USER"

# 检查 crontab 中是否已经有该脚本的任务
if crontab -l 2>/dev/null | grep -q "$path"; then
ip4
else
# 如果 crontab 中没有任务,添加任务
(crontab -l 2>/dev/null; echo "${time} ${path}") | crontab -
fi
```bash
#!/bin/bash

# 定义函数
ip4() {
local da=$(date)
local ta=$(ip addr show eth0 | grep "/24" | awk '{print $2}' | cut -d'/' -f1)
echo "$da 当前IP地址为:$ta" >> /tmp/ip.txt
}

# 获取脚本的绝对路径
path="$(realpath "$0")"
time="* 6 * * * $USER"

# 检查 crontab 中是否已经有该脚本的任务
if crontab -l 2>/dev/null | grep -q "$path"; then
ip4
else
# 如果 crontab 中没有任务,添加任务
(crontab -l 2>/dev/null; echo "${time} ${path}") | crontab -
fi

Pasted-image-20241130211535

无线重启脚本

  • 知道前面计划任务,尝试编写一个开机就启动的计划任务(暂不知道什么问题,无法实现)
#!/bin/bash
# 获取当前脚本的绝对路径

path="$(realpath "$0")"
# 定义 @reboot 时间格式
time="@reboot $USER "
# 检查 crontab 中是否已经有该脚本的任务

if crontab -l 2>/dev/null | grep -q "$path"; then
    sleep 3
    shutdown -r now   # 如果任务已存在,重新启动系统
else
    # 如果任务不存在,添加定时任务到 crontab
    echo "${time}${path}" | crontab -
    sleep 3
    shutdown -r now
fi
```bash
#!/bin/bash
# 获取当前脚本的绝对路径

path="$(realpath "$0")"
# 定义 @reboot 时间格式
time="@reboot $USER "
# 检查 crontab 中是否已经有该脚本的任务

if crontab -l 2>/dev/null | grep -q "$path"; then
    sleep 3
    shutdown -r now   # 如果任务已存在,重新启动系统
else
    # 如果任务不存在,添加定时任务到 crontab
    echo "${time}${path}" | crontab -
    sleep 3
    shutdown -r now
fi

  • 利用systemd实现开机执行脚本重启
[Unit]
Description=reboot
After=multi-user.target

[Service]
ExecStart=$SH_PATH
Restart=always
User=root

[Install]
WantedBy=multi-user.target
```bash
[Unit]
Description=reboot
After=multi-user.target

[Service]
ExecStart=$SH_PATH
Restart=always
User=root

[Install]
WantedBy=multi-user.target

  • [Unit] 部分定义了服务的描述和它的启动顺序。

    • Description 是对服务的简短描述。
    • multi-user.target 系统启动并进入多用户模式后
  • [Service] 部分定义了服务的运行方式。

    • ExecStart 指定了启动脚本的命令。
    • Restart=always 表示如果脚本崩溃,会自动重新启动。
    • User=root 指定以哪个用户身份运行脚本。
  • [Install] 部分定义了在何时启用该服务。

    • WantedBy=multi-user.target 表示该服务将在系统进入多用户模式时启动,通常这是默认的运行级别。
  • 最终编写脚本

#!/bin/bash 

# 定义函数
rb() {
    echo -e "[Unit]\nDescription=reboot\nAfter=multi-user.target\n\n[Service]\nExecStart=$SH_PATH\nRestart=always\nUser=root\n\n[Install]\nWantedBy=multi-user.target" > "/etc/systemd/system/reboot.service"
    systemctl daemon-reload
    systemctl enable reboot
    systemctl start reboot
    reboot
}
ID_PATH="/etc/systemd/system/reboot.service"
SH_PATH="$(realpath "$0")"
if [ -f $ID_PATH ]; then
    reboot
else
    rb
fi
```bash
#!/bin/bash

# 定义函数
rb() {
    echo -e "[Unit]\nDescription=reboot\nAfter=multi-user.target\n\n[Service]\nExecStart=$SH_PATH\nRestart=always\nUser=root\n\n[Install]\nWantedBy=multi-user.target" > "/etc/systemd/system/reboot.service"
    systemctl daemon-reload
    systemctl enable reboot
    systemctl start reboot
    reboot
}
ID_PATH="/etc/systemd/system/reboot.service"
SH_PATH="$(realpath "$0")"
if [ -f $ID_PATH ]; then
    reboot
else
    rb
fi

PixPin_2024-12-08_17-01-26