Shell 脚本入门指南

news2024/9/24 21:28:06

Shell 脚本入门指南

  • 引言
    • 1.1 什么是 Shell 脚本?
    • 1.2 为什么学习 Shell 脚本?
  • 准备工作
    • 2.1 选择和安装 Shell(Bash)
    • 2.2 设置脚本编辑环境(文本编辑器)
  • Hello World!
  • 基本语法
    • 4.1 变量
    • 4.2 条件判断
    • 4.3 循环
  • 文件和目录操作
  • 函数
  • 简单实用脚本示例
    • 7.1 自动化备份脚本
    • 7.2 添加定时任务

引言

1.1 什么是 Shell 脚本?

Shell 脚本是一种用于自动化任务的脚本语言,通常在 Unix/Linux 系统中使用。通过结合条件判断和循环来实现命令的自动运行以完成一些相对固定的操作。

1.2 为什么学习 Shell 脚本?

Shell 脚本可以简化系统管理任务、自动化重复性工作、提高工作效率。并且维护简单,实际应用中非常有用。另外我们还可以在脚本文件中设置环境变量,方便管理每个项目不同的环境变量。

准备工作

2.1 选择和安装 Shell(Bash)

大多数 Linux 发行版默认安装了 Bash,可以通过 bash --version 检查。本文演示的系统环境为Linux。
在这里插入图片描述

2.2 设置脚本编辑环境(文本编辑器)

推荐使用简单的文本编辑器如 nano、vim 或者图形化编辑器如 VS Code。本文使用推荐使用功能强大的vim编辑器。

Hello World!

现在我们先从一个简单的hello world文件开始本文的学习。该样例通过读取用户输入的循环次数来打印字符串“hello world”。

test.sh

#!/bin/bash

# 提示用户输入循环次数
echo "请输入循环次数:"
read count

# 检查输入是否为有效的数字
if [ "$count" lt 0 ]; then
    echo "请输入一个有效的数字。"
    exit 1
fi

# 使用 for 循环打印 "hello world"
for ((i = 1; i <= count; i++))
do
    echo "hello world"
done

下面是对代码的解释:
#!/bin/bash 是一个称为 “shebang” 的特殊注释行,它告诉操作系统使用哪个解释器来执行脚本。Linux有很多的解释器,不同的解释器语法略有不用。
使用 echo 命令提示用户输入,然后使用read命令读取用户输入并存储在变量 count 中。
使用 if 语句和 -lt 比较操作符检查 count 是否小于 0。如果是,则提示用户输入一个非负数并退出脚本。
使用 for 循环从 1 到 count,每次循环打印 “hello world”。

运行sh test.sh或./test.sh效果如下:
在这里插入图片描述
如果发现运行失败则有可能是脚本文件的权限不够,解决方案如下:

使用chmod a+x test.sh命令手动给文件添加权限。

基本语法

通过上面一个简单的hello world样例我们已经初步的认识了bash shell脚本文件。接下来就开始系统的学习shell的一些基本语法。

4.1 变量

变量是用来存储数据的值的名称,和其他高级编程语言的变量含义一样。同时也拥有和其他高级编程语言对变量命名上的限制:

1:字母和数字:变量名只能包含字母(a-z, A-Z)、数字(0-9)和下划线(_)。
2:不能以数字开头:变量名不能以数字开头。例如,1variable 是无效的,而 variable1 是有效的。
3:区分大小写:变量名是区分大小写的。例如,VAR 和 var 是两个不同的变量。
4:避免使用特殊字符:避免在变量名中使用特殊字符(如 !, @, #, $, %, ^, &, (, ), -, +, =, :, ;, ", ', ,?, / 等)。

变量命名惯例:

使用大写字母:环境变量和常量通常使用大写字母。例如,PATH, HOME, USER。
使用小写字母:普通变量通常使用小写字母。例如,filename, count, index。
使用下划线分隔单词:为了提高可读性,可以使用下划线分隔单词。例如,file_name, user_count。

无效的变量命名:

1variable 不能以数字开头
file-name 不能包含连字符
user@name 不能包含特殊字符

有效的变量命名:

filename
file_name
userCount
USER_COUNT
_var123

在 Shell 中,变量赋值时不需要使用等号两边的空格:

variable_name=value 正确示例
variable_name = value 错误示例

定义好变量之后,我们需要后续的代码中使用时也与高级编程语言有所不同。使用变量时,需要在变量名前加上美元符号$

echo $name
echo $age

如果变量名紧跟在其他字符后面,可以使用花括号 {} 来明确变量名的边界:

echo “Hello, ${name}”

另外还有一些特殊的变量,比如$1表示传递给脚本或者函数的第一个参数。
我们对上面的hello world代码做一些改变,以遍在运行脚本时就获取循环的次数。
test.sh

#!/bin/bash

# 提示用户输入循环次数
# echo "请输入循环次数:"
# read count

count=$1
# 检查输入是否为有效的数字
if [ "$count" lt 0 ]; then
    echo "请输入一个有效的数字。"
    exit 1
fi

# 使用 for 循环打印 "hello world"
for ((i = 1; i <= count; i++))
do
    echo "hello world"
done

运行脚本:sh test.sh 3
在这里插入图片描述
上述代码获取循环次数的方式便不再是通过输入读取,而是传参的方式获取,注意两种方式的运行情况。

4.2 条件判断

在上一节中我们的脚本文件还运用了if判断语句来保证循环的次数不是负数。本节就来详细介绍条件判断的语法。

if else语法格式:

if condition
then
	...
fi
# 也可采用不同风格的缩进风格
if condition; then
	...
fi
# 或是写成一行
if condition; then ...; fi

一定要注意不同缩进风格的空格控制,少了空格或多了空格都会导致脚本运行报错,因为一定要格外注意。

在condition中通过涉及到对整数以及字符串的判断,如下所示:

运算符作用
-eq是否等于(=)
-ne是否不等于(!=)
-gt是否大于 (>)
-lt是否小于 (<)
-le是否小于或等于(<=)
-ge是否大于或等于(>=)
运算符作用
=比较字符串内容是否相同
!=比较字符串内容是否不相同
-z比较字符串内容是否为空

下面来看一下使用示例:
condition.sh

#!/bin/bash

a=10
b=20

if [ $a gt $b ]; then
  echo "${a} 大于 ${b}"
 
else
  echo "${a} 小于等于 ${b}"
fi

运行sh condition.sh
在这里插入图片描述
用过上述也向大家介绍了if else的结构语法

if condition then;
	...
else
	...
fi

另外还有if else if结构

if condition1
then
    ...
elif condition2 
then 
    ...
else
    ...
fi

大家自行验证。

在上述条件判断表达式中我们都是使用的[ … ](注意空格),但是还可以使用(( … ))这种双括号的形式来替换[ … ],并且这样做的好处是可以直接使用我们常见的<,>,!=,=等直接对数字进行判断。

#!/bin/bash

a=10
b=20

if (( $a > $b )); then
  echo "${a} 大于 ${b}"
 
else
  echo "${a} 小于等于 ${b}"
fi

有人可能已经发现了上述我们说的都是整数的比较,那浮点数怎么比较呢。

使用 bc 进行浮点数比较
bc 是一个强大的工具,可以处理浮点数运算。以下是一个示例,演示如何使用 bc 来比较两个浮点数:

#!/bin/bash

echo "请输入第一个浮点数:"
read num1
echo "请输入第二个浮点数:"
read num2

# 使用 bc 进行比较
if [ "$(echo "$num1 > $num2" | bc)" -eq 1 ]; then
    echo "$num1 大于 $num2"
elif [ "$(echo "$num1 < $num2" | bc)" -eq 1 ]; then
    echo "$num1 小于 $num2"
else
    echo "$num1 等于 $num2"
fi

解释:

使用 echo 将比较表达式传递给 bc,然后使用 bc 进行计算。bc 返回 1 表示真,返回 0 表示假。然后再对bc返回的结果进行比较,如果是1,则num1大于num2。

也可以使用 awk 进行浮点数的比较,用法自行搜索

4.3 循环

常见的循环结构包括 for 循环、while 循环和 until 循环。

# for 循环用于遍历一组值或列表。它的基本语法如下:
for variable in list
do
    ...
done

# 使用示例:
for item in apple banana cherry
do
    echo "Fruit: ${item}"
done
# while 循环在给定条件为真时重复执行一组命令。它的基本语法如下:
while condition
do
    ...
done
# 使用示例;
count=1
while (( count <= 5 ))
do
    echo "Count: ${count}"
    count=$((count + 1))
done
# 与while正好相反,在循环在给定条件为假时重复执行一组命令
until condition
do
    ...
done

# 使用示例:
#!/bin/bash

# 使用 until 循环打印数字 1 到 5
count=1
until (( $count > 5 ))
do
    echo "Count: ${count}"
    count=$((count + 1))
done

循环可以嵌套使用,即在一个循环内部包含另一个循环。

for i in {1..3}
do
    for j in {1..3}
    do
        result=$((i * j))
        echo "${i} * ${j} = ${result}"
    done
done

在循环中,可以使用 break 和 continue 控制循环的执行。

  • break:立即退出整个循环。
  • continue:跳过当前迭代,继续下一次迭代
#!/bin/bash

# 使用 break 和 continue 控制循环
for i in {1..5}
do
    if [ $i -eq 3 ]; then
        continue  # 跳过当前迭代
    fi
    if [ $i -eq 5 ]; then
        break  # 退出循环
    fi
    echo "Number: ${i}"
done

还有一种特殊的结构case…case
case 语句在 Shell 脚本中用于多分支条件判断,类似于其他编程语言中的 switch 语句。

case variable in
    pattern1)
        commands1
        ;;
    pattern2)
        commands2
        ;;
    pattern3)
        commands3
        ;;
    *)
        default_commands
        ;;
esac

# 使用示例:
echo "请输入一个选项 (start/stop/restart/status):"
read option

case $option in
    start)
        echo "启动服务..."
        # 在这里添加启动服务的命令
        ;;
    stop)
        echo "停止服务..."
        # 在这里添加停止服务的命令
        ;;
    restart)
        echo "重启服务..."
        # 在这里添加重启服务的命令
        ;;
    status)
        echo "查看服务状态..."
        # 在这里添加查看服务状态的命令
        ;;
    *)
        echo "无效的选项,请输入 start, stop, restart 或 status。"
        ;;
esac

文件和目录操作

下面给出一些常用的文件和目录的判断操作:

判断文件是否存在

if [ -f "filename" ]; then
    echo "文件存在"
else
    echo "文件不存在"
fi

判断目录是否存在

if [ -d "directoryname" ]; then
    echo "目录存在"
else
    echo "目录不存在"
fi

判断文件或目录是否存在

if [ -e "path" ]; then
    echo "文件或目录存在"
else
    echo "文件或目录不存在"
fi

获取文件的大小

filesize=$(stat -c%s "filename")
echo "文件大小: $filesize 字节"

使用 while 循环逐行读取文件内容

while IFS= read -r line  # line为filename文件的每一行内容
do
    echo "${line}"
done < "filename"

使用重定向写入文件

echo “一些内容” > filename 覆盖写入
echo “一些内容” >> filename 追加写入

结合常用的Linux命令能让你的脚本文件更加完善健壮,实现更高的自动化工作。

函数

函数的简单定义形式为:

func() {
    ...
    return $((...))
}

下面我们写一个简单的计算两数之和的函数,并通过 $? 获取函数的返回值进行打印。

#!/bin/bash

add(){
    echo "输入第一个数字: "
    read a
    echo "输入第二个数字: "
    read b
    return $(($a+$b))
}
add # 调用函数
echo "输入的两个数字之和为 $? !"# $?获取上个命名或函数的返回结果。

请注意与高级编程语言一样,函数在调用之前必须存在对其的定义,可以把调用放在文件的第二行看看会发生什么?。

与高级编程语言不同的是,这里的return其实不能叫做函数的返回结果,更应该叫做函数的返回状态码,返回状态码是有范围限制的(0 - 255之间 ),返回码常用来表示函数的或者命名的执行情况,比如常见的0表示成功,1表示失败等等。所以我们不应该使用return返回计算的结果。

我们可以使用echo来代替return进行返回:

#!/bin/bash

add() {
    echo "输入第一个数字: "
    read a
    echo "输入第二个数字: "
    read b
    echo $(($a + $b))  # 使用 echo 输出结果
}
add

在Shell中,调用函数也时可以向其传递参数。在函数体内部,通过 $n 的形式来获取参数的值,例如,$1表示第一个参数,$2表示第二个参数…

#!/bin/bash

func(){
    echo "第一个参数为 $1 !"
    echo "第二个参数为 $2 !"
    echo "第十个参数为 $10 !"
    echo "第十个参数为 ${10} !"
    echo "第十一个参数为 ${11} !"
    echo "参数总数: $# 个"
    echo "作为一个字符串输出所有参数: $* "
}
funWithParam 1 2 3 4 5 6 7 8 9 34 73

这点我们在变量那节的结尾也有提到。

简单实用脚本示例

7.1 自动化备份脚本

#!/bin/bash

# 全局变量
BACKUP_DIR="/path/to/backup"
LOG_FILE="/path/to/logfile.log"
MAX_RETRIES=3

# 函数:记录日志
log_message() {
	# local表示局部变量
    local message=$1
    echo "$(date +'%Y-%m-%d %H:%M:%S') - ${message}" >> ${LOG_FILE} # 以追加的方式将日志记录在日志文件中
}

# 函数:备份数据库
backup_database() {
    local db_name=$1
    local backup_file="${BACKUP_DIR}/${db_name}_$(date +%Y%m%d).sql"
    
    log_message "开始备份数据库 ${db_name}${backup_file}..."
    # 假设使用 mysqldump 进行备份
    mysqldump ${db_name} > ${backup_file}
    
    if [ $? -eq 0 ]; then # 这里的$?拿到的就是mysqldump的执行结果
        log_message "备份成功"
    else
        log_message "备份失败"
    fi
}

# 函数:生成报告
generate_report() {
    local report_file=$1
    
    log_message "生成报告到 ${report_file}..."
    # 假设生成一个简单的报告
    echo "报告内容" > ${report_file}
    
    if [ $? -eq 0 ]; then
        log_message "报告生成成功"
    else
        log_message "报告生成失败"
    fi
}

# 函数:检查备份目录是否存在
check_backup_dir() {
	# !表示逻辑取反
    if [ ! -d ${BACKUP_DIR} ]; then
        log_message "备份目录 ${BACKUP_DIR} 不存在,创建中..."
        mkdir -p ${BACKUP_DIR}
        
        if [ $? -eq 0 ]; then
            log_message "备份目录创建成功"
        else
            log_message "备份目录创建失败"
            exit 1
        fi
    fi
}

# 主程序
main() {
    local db_name="example_db"
    local report_file="/path/to/report.txt"
    
    check_backup_dir
    backup_database ${db_name}
    generate_report ${report_file}
}

# 执行主程序
main

7.2 添加定时任务

我们可以为脚本文件添加定时策略,以便在凌晨或者其他时间点不用程序员再自己打开电脑手动运行脚本。

我们使用Linux系统默认启用的crond服务就是用来干这事的:
crond 是 Linux 和 Unix 系统中的一个守护进程,用于定期执行计划任务。它通过读取配置文件(通常是 crontab 文件)来确定何时执行哪些任务。

crontab -l:列出当前用户的 crontab 文件内容。

在这里插入图片描述

可以看到目前用户还没有crontab文件。接下我们使用crontab -e:

crontab -e:编辑当前用户的 crontab 文件。

在crontab文件中输入19 17 * * * /data/home/tommwwu/shell-test/func.sh。定时策略,解释如下:

* * * * * command
- - - - -
| | | | |
| | | | +---- 星期几 (0 - 7) (07 都表示星期天)
| | | +------ 月份 (1 - 12)
| | +-------- 一个月中的第几天 (1 - 31)
| +---------- 小时 (0 - 23)
+------------ 分钟 (0 - 59)

1 * * * * /data/home/tommwwu/shell-test/func.sh的意思就是这个func.sh脚本会在每天下午的17:19分执行一次。

crontab -r:删除当前用户的 crontab 文件。
定时任务执行,日志一般输出在

在这里插入图片描述

在大多数 Linux 系统中,cron 的日志记录在 /var/log/cron 或 /var/log/syslog 中。如下:
在这里插入图片描述
另外在crontab配置文件中还可以设置环境变量等

SHELL=/bin/bash 指定使用的 shell
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin 指定命令的搜索路径。
MAILTO=user@example.com 指定任务执行结果的邮件接收者。

完。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2084229.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【OpenCV】离散傅里叶变换

离散傅里叶变换 傅里叶变换代码实现扩展图片创建储存实部和虚部值的矩阵进行离散傅里叶变换将复数转换成振幅对数转换裁剪和重排归一化 离散傅里叶变换在图像处理中的应用参考 傅里叶变换 在图片处理中&#xff0c;傅里叶变化会将对图片的时域分析转变为频域分析。 傅里叶的基…

模型 麦肯锡七步成诗法

系列文章 分享 模型&#xff0c;了解更多&#x1f449; 模型_思维模型目录。问题到解决方案的七步跨越。 1 麦肯锡七步成诗法的应用 1.1零售业客户体验转型实践 随着消费者对购物体验的要求日益提高&#xff0c;一家零售企业面临客户流失和销售增长放缓的问题。企业管理层决定…

分类预测|基于哈里斯鹰优化混合核极限学习机的数据分类预测Matlab程序HHO-HKELM多特征输入多类别输出含基础程序

分类预测|基于哈里斯鹰优化混合核极限学习机的数据分类预测Matlab程序HHO-HKELM多特征输入多类别输出含基础程序 文章目录 前言分类预测|基于哈里斯鹰优化混合核极限学习机的数据分类预测Matlab程序HHO-HKELM多特征输入多类别输出含基础程序 一、HHO-HKELM模型HHO-HKELM 分类预…

告别PDF格式困扰,2024年PDF转换器推荐

PDF现在已经逐渐成为了文件传输的主流格式了&#xff0c;它有保存文件页面版式的优点&#xff0c;但是这个格式编辑对大部分人来说还是不那么方便&#xff0c;日常我们还是习惯将它们转换成我们常见的 文本格式来操作。今天我分享一下可以实现PDF格式转换的pdf转换器有哪些吧。…

CSS3实现购物车动画效果

概述 小程序商城或者 web 端网站时,我们可以只通过 CSS 的 animation 和transform,而不需要借助额外的第三方库轻松实现简单的动画效果,丰富页面的表达效果 效果 如下图所示,点击按钮就会有个商品进入左下角的购物车内 购物车动画示例地址 代码示例 元素 开始只需要写…

Uniapp 调用aar、jar包

废话 坑是真的多&#xff0c;官方文档简陋到可以忽略不计。 大概流程 1. 新建一个Android模块&#xff0c;需要用这个模块打包成aar 2. 用这个模块引用uniapp-v8-release.aar以及你需要用到的aar、jar&#xff0c;用不到则忽略这步 坑一&#xff1a;不要直接放到这个模块的…

window11彻底关闭Microsoft Defender

Microsoft Defender Antivirus 是 Microsoft Windows 11 操作系统的默认防病毒解决方案。默认情况下它处于打开的状态。大多数第三方的杀毒软件都可以识别&#xff0c;并代替它。 但是大多数情况下&#xff0c;我们总是有各种理由需要关闭它&#xff0c;例如 Windows Defender …

轻量级冠军:NVIDIA 发布具有领先准确率的小语言模型

Mistral-NeMo-Minitron 8B 是最近发布的 Mistral NeMo 12B 模型的微型版本&#xff0c;具有高精度和高计算效率&#xff0c;可在 GPU 加速数据中心、云和工作站上运行模型。 生成式 AI 开发者通常需要在模型尺寸和准确性之间做出权衡。然而&#xff0c;NVIDIA 发布的一款新语言…

内存管理篇-14kmalloc机制实现分析

引入这个kmalloc的目的&#xff0c;是因为前面的slab接口太过于复杂&#xff0c;因此需要一个全新的封装kmalloc接口&#xff0c;内存申请编程接口实现。kmalloc底层起始也是基于slab缓存实现的。 1.kmalloc 调用流程 参数解析: 解析 gfp_mask 参数&#xff0c;确定分配时是否…

数据结构与算法学习day18-层序遍历

层序遍历一个二叉树。就是从左到右一层一层的去遍历二叉树。这种遍历的方式和我们之前讲过的都不太一样。需要借用一个辅助数据结构即队列来实现&#xff0c;队列先进先出&#xff0c;符合一层一层遍历的逻辑&#xff0c;而用栈先进后出适合模拟深度优先遍历也就是递归的逻辑。…

硬盘崩溃数据无踪?Windows数据恢复TOP4揭秘,2024年助你找回宝贵资料

现在我们的生活、工作、学习都离不开电脑&#xff0c;电脑里的硬盘就像个装满宝贝的箱子&#xff0c;里面全是我们宝贵的照片、文档、视频和美好回忆。但要是硬盘突然坏了&#xff0c;东西一下子全没了&#xff0c;那感觉真是太糟糕了。别担心&#xff0c;今天我们就给你介绍几…

2024年中国运筹学会运筹竞赛(数据驱动赛道)报名通知

竞赛组织 主办单位&#xff1a;中国运筹学会&#xff08;国家一级学会&#xff09; 承办单位&#xff1a;中国科学技术大学 支持单位&#xff1a;杉数科技、海康威视、中国科学技术大学管理学院、《运筹学学报》杂志 竞赛内容 本次竞赛&#xff08;本科生组&#xff09;由竞…

不平衡数据集的单类分类算法

不平衡数据集的单类分类算法 异常值或异常是与其他数据不符的罕见例子。 识别数据中的离群值称为离群值或异常检测&#xff0c;机器学习中专注于此问题的子领域称为单类分类。这些是无监督学习算法&#xff0c;旨在对“正常”示例进行建模&#xff0c;以便将新示例分类为正常…

记录一次给iOS 工程添加.gitignore文件

新建了一个iOS工程&#xff0c;修改过代码之后&#xff0c;提交发现有一些自己不想要提交的内容 如下图&#xff0c;里面有.DS_Store文件&#xff0c;还有xcsuserstate文件&#xff0c; 这个时候需要添加忽略文件 首先在工程文件夹中执行 touch .gitignore 创建忽略文件&#…

Unity2D游戏开发-Pak木鱼

在接下来文章里我会以Unity为主一起制作游戏 在unity 里如何制作一个简单的敲木鱼游戏&#xff1f; 创建一个2D场景&#xff08;本人使用Unity2023&#xff09; (每个一段时间要申请一个个人许可证) 点击下方蓝色按钮创建 将以下素材拖动到Assets文件夹中 这张图随意命名我…

Swift concurrency 4 — Task和.task的理解与使用

Task Swift中的Task是一种异步操作&#xff0c;它提供了一种替代DispatchQueue.main.async{}等传统方法的方法。通过使用Task&#xff0c;我们可以简化代码并更好地控制异步操作。此外&#xff0c;Task还提供了其他选项&#xff0c;可以进一步增强任务执行。 先看一个Task的基…

net core中byte数组如何高效转换为16进制字符串

在 .NET Core 中&#xff0c;如何把 byte[] 转换为 16 进制字符串&#xff1f;你能想到哪些方法&#xff1f;什么方式性能最好&#xff1f;今天和大家分享几种转换方式。 往往在处理字符串性能问题时&#xff0c;首先应该想到的是怎么想办法减少内存分配&#xff0c;怎么优化字…

22.优化器

优化器 当使用损失函数时&#xff0c;可以调用损失函数的 backward&#xff0c;得到反向传播&#xff0c;反向传播可以求出每个需要调节的参数对应的梯度&#xff0c;有了梯度就可以利用优化器&#xff0c;优化器根据梯度对参数进行调整&#xff0c;以达到整体误差降低的目的。…

Cryptomator:开源云存储加密

采用最新技术标准&#xff0c;提供最佳保护 如果有人查看您云中的文件夹&#xff0c;他们无法对您的数据得出任何结论。 Cryptomator 提供开源的客户端云文件加密。 它适用于 Windows、Linux、macOS 和 iOS。 Cryptomator 可与 Dropbox、Google Drive、OneDrive、MEGA、pClo…

【QT | 开发环境搭建】Linux系统(Ubuntu 18.04) 安装 QT 5.12.12 开发环境

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; ⏰发布时间⏰&#xff1a; 2024-08-29 …