当前位置: 首页 > news >正文

Shell 脚本开发从入门到实战

第1章:什么是 Shell 与 Shell 脚本?

一、Shell 是什么?

  • Shell 是一个命令解释器,是你在 Linux 里敲命令的地方。
  • 你平时用的命令如 cdlsecho,其实都由 Shell 来解析执行。
  • 最常见的 Shell 是 Bash,绝大多数 Linux 系统默认都用它。

二、什么是 Shell 脚本?

  • Shell 脚本就是一系列 Shell 命令的集合,保存成一个 .sh 文件。
  • 本质上:你平时一条一条敲的命令,写成脚本就能一次性自动运行。
  • 示例场景:
    • 每天定时备份数据库
    • 启动一堆服务
    • 自动上传文件、发通知等

三、第一个 Shell 脚本实战

步骤1:创建一个脚本文件
vim hello.sh
步骤2:写入下面内容
#!/bin/bash
# 这是我的第一个Shell脚本echo "Hello, Shell!"

第一行 #!/bin/bash 是固定写法,告诉系统用 Bash 来执行脚本。

步骤3:保存退出并赋予执行权限
chmod +x hello.sh
步骤4:运行脚本
./hello.sh

输出应该是:

Hello, Shell!

四、脚本中的几个细节

  • 所有行首以 # 开头的是注释,系统会忽略。
  • 每一行相当于你在终端执行的一条命令。
  • 脚本默认按顺序逐行执行。

五、本节练习

自己创建一个脚本 myinfo.sh,内容如下:

#!/bin/bashecho "欢迎来到 Shell 脚本世界!"
echo "当前用户:$USER"
echo "当前时间:$(date)"
echo "当前目录:$(pwd)"

运行后会打印你的用户名、当前时间和所在目录。


第2章:变量与运算符

一、变量的定义与使用

1. 定义变量(= 两边不能有空格)
name="张三"
age=25
2. 使用变量:$变量名${变量名}
echo "姓名:$name"
echo "年龄:${age}"

二、变量赋值的注意事项

a=10          # 正确
a = 10        # 错误,不能有空格

三、特殊变量

变量说明
$0当前脚本名称
$1~$9传入脚本的第1~9个参数
$@传入的所有参数(可用于循环)
$#参数个数
$$当前脚本的进程ID
$?上一条命令的返回值(0成功,非0失败)
示例:
#!/bin/bash
echo "脚本名:$0"
echo "第一个参数:$1"
echo "参数个数:$#"

运行:

./myscript.sh hello

输出:

脚本名:./myscript.sh
第一个参数:hello
参数个数:1

四、字符串操作

拼接字符串:
first="张"
last="三"
full=$first$last
echo "姓名:$full"
获取字符串长度:
str="abc123"
echo "长度:${#str}"  # 输出 6

五、数值运算(整数)

Bash 默认只支持整数,用三种方式:

1. 使用 let
let a=5+3
echo $a  # 输出 8
2. 使用 expr
a=`expr 5 + 3`
echo $a

注意:运算符前后必须有空格。

3. 使用 $((...))(推荐)
a=$((5 + 3))
echo $a

六、本节小练习

请写一个脚本:userinfo.sh,功能如下:

#!/bin/bashname="李四"
age=30
year=$((2025 - age))echo "姓名:$name"
echo "年龄:$age"
echo "出生年份:$year"

运行后输出:

姓名:李四
年龄:30
出生年份:1995

第3章:流程控制语句(if / case / for / while)

一、if 判断语句

基本语法:
if [ 条件 ]
then命令1命令2
fi
示例:
age=20if [ $age -ge 18 ]; thenecho "成年人"
elseecho "未成年人"
fi
常用条件判断符号:
条件含义
-eq等于
-ne不等于
-gt大于
-lt小于
-ge大于等于
-le小于等于
== / !=字符串比较

二、文件判断(常用于运维脚本)

if [ -f "a.txt" ]; thenecho "a.txt 是一个文件"
fiif [ -d "/home" ]; thenecho "/home 是一个目录"
fi
表达式含义
-f FILE是否是普通文件
-d DIR是否是目录
-e FILE是否存在
-r/-w/-x FILE是否可读 / 可写 / 可执行

三、case 多分支选择(类似 switch)

read -p "请输入操作命令(start|stop|restart):" cmdcase $cmd instart)echo "正在启动服务...";;stop)echo "正在停止服务...";;restart)echo "正在重启服务...";;*)echo "未知命令";;
esac

四、for 循环

遍历列表:
for name in 张三 李四 王五
doecho "你好,$name"
done
遍历数字:
for i in {1..5}
doecho "第 $i 次"
done

五、while 循环

i=1
while [ $i -le 5 ]
doecho "当前是第 $i 次"i=$((i + 1))
done

六、本节练习题

写一个脚本 score.sh

#!/bin/bashread -p "请输入成绩:" scoreif [ $score -ge 90 ]; thenecho "优秀"
elif [ $score -ge 70 ]; thenecho "良好"
elif [ $score -ge 60 ]; thenecho "及格"
elseecho "不及格"
fi

第4章:函数与脚本模块化

在脚本越来越复杂时,把逻辑封装成函数可以让脚本更清晰、复用性更强。


一、函数的定义与调用

语法1:带 function 关键字
function say_hello() {echo "Hello!"
}
语法2:省略 function
say_hello() {echo "Hello!"
}
调用函数:
say_hello

二、函数传参

函数可以像脚本一样,通过 $1$2 来接收参数:

greet() {echo "你好,$1!今天是 $2。"
}greet "张三" "星期四"

输出:

你好,张三!今天是 星期四。

三、函数返回值

  • return 只能返回 整数(状态码),不适合传数据
  • 可以通过 echo 输出 + 命令替换的方式返回字符串
示例1:返回状态码
check_even() {if [ $(( $1 % 2 )) -eq 0 ]; thenreturn 0elsereturn 1fi
}check_even 4
if [ $? -eq 0 ]; thenecho "偶数"
elseecho "奇数"
fi
示例2:返回字符串
get_name() {echo "张三"
}name=$(get_name)
echo "姓名是:$name"

四、脚本模块化(多个脚本协作)

你可以将常用函数写在一个文件里,用其他脚本通过 source 引入使用。

step1:创建函数库 utils.sh
say_hi() {echo "你好,我是工具函数"
}
step2:主脚本中引入使用
#!/bin/bash
source ./utils.shsay_hi

五、本章练习

写一个函数 calc_sum,输入两个参数,输出它们的和:
calc_sum() {sum=$(( $1 + $2 ))echo "$1 + $2 = $sum"
}calc_sum 4 6

第5章:文件判断、重定向与文本处理


一、文件存在性与属性判断

1. 判断文件是否存在
if [ -e "file.txt" ]; thenecho "文件存在"
fi
2. 常用文件判断符号
表达式含义
-e file是否存在
-f file是否是普通文件
-d dir是否是目录
-s file文件非空
-r file是否可读
-w file是否可写
-x file是否可执行
示例:判断一个目录是否存在,不存在则创建
dir="/data/backup"
if [ ! -d "$dir" ]; thenmkdir -p "$dir"echo "目录已创建:$dir"
elseecho "目录已存在:$dir"
fi

二、输入输出重定向

1. 重定向输出(覆盖 / 追加)
echo "一行内容" > file.txt     # 覆盖写入
echo "再来一行" >> file.txt    # 追加写入
2. 重定向错误输出
command 2> error.log   # 仅错误输出到 error.log
command > out.log 2>&1 # 正常和错误都写入 out.log

三、文本内容处理:核心工具

1. cat:查看文件内容
cat file.txt
2. head / tail:查看前几行/后几行
head -n 5 file.txt
tail -n 10 file.txt
3. cut:按列提取文本内容
cat users.csv | cut -d ',' -f 2   # 提取第2列(用,分隔)
4. grep:关键词搜索
grep "ERROR" /var/log/syslog
5. awk:按列处理文本,超强工具
awk -F ',' '{print $1, $3}' users.csv
6. sed:流编辑器,可做替换、删除行等
sed 's/错误/成功/g' log.txt     # 全文替换
sed -n '5,10p' file.txt         # 显示第5到10行

四、本章综合示例

日志扫描:提取最近系统错误日志
#!/bin/bash
log="/var/log/syslog"grep "ERROR" "$log" | tail -n 20 > recent_errors.log
echo "最近错误已提取到 recent_errors.log"
CSV 提取:获取手机号列表(第3列)
#!/bin/bash
cut -d ',' -f 3 users.csv > phones.txt
echo "手机号已提取完毕"

五、本章练习题

  1. 判断 /etc/passwd 文件是否存在,如果存在则统计其行数。
  2. 提取 backup.log 文件中最近的包含关键字 fail 的前 10 条记录。
  3. data.txt 中的所有 “null” 替换为 “空值”。

第6章:Shell 工具组合实战(find、xargs、tar、scp、curl 等)


一、find:查找文件

基本用法
find 路径 [条件] [操作]
常见示例
# 查找所有 .log 文件
find /var/log -name "*.log"# 查找3天前修改的文件
find /data -mtime +3# 查找大于100M的文件
find / -type f -size +100M# 查找并删除7天前的备份文件
find /backup -name "*.tar.gz" -mtime +7 -exec rm -f {} \;

二、xargs:批量传参执行命令

cat files.txt | xargs rm -f

或结合 find 使用:

find . -name "*.tmp" | xargs rm -f

xargs 是 Shell 脚本中实现批处理的“神器”。


三、tar:打包压缩备份

# 打包当前目录
tar -czvf backup.tar.gz ./# 解压
tar -xzvf backup.tar.gz -C /tmp

四、scp:远程复制文件

# 上传文件
scp localfile.txt user@remote:/data/# 下载文件
scp user@remote:/data/backup.tar.gz ./

配合 SSH 免密登录使用更方便。


五、rsync:增量同步工具(强烈推荐用于部署)

rsync -avz ./dist/ user@remote:/data/web/
  • -a:归档模式(保留时间、权限等)
  • -v:显示详细过程
  • -z:压缩传输

六、curl:调用接口(之前已经讲过)

常用于脚本中调用 webhook、发送通知、上报状态等。

curl -X POST http://api.example.com/report \-H "Content-Type: application/json" \-d '{"status":"ok","time":"2025-04-10 12:00:00"}'

七、本章综合实战:自动打包 + 清理 + 上报

#!/bin/bash# 定义变量
BAK_DIR="/data/backup"
NOW=$(date +"%Y%m%d%H%M%S")
FILENAME="backup_$NOW.tar.gz"# 打包
tar -czf "$BAK_DIR/$FILENAME" /data/mingdao# 删除7天前的旧备份
find $BAK_DIR -name "*.tar.gz" -mtime +7 -exec rm -f {} \;# 上报结果
curl -X POST http://api.example.com/backup/report \-H "Content-Type: application/json" \-d "{\"filename\":\"$FILENAME\", \"time\":\"$NOW\"}"

八、本章练习题

  1. 使用 find 查找 /tmp 目录下所有 .log 文件并删除。
  2. 编写一个脚本:打包 /etc 目录,保存到 /data/backup,并保留最近3份。
  3. 编写一个自动化部署脚本,使用 rsync 将本地 /dist 同步到远程服务器指定目录。

第7章:Shell 实战项目篇


实战1:数据库定时备份 + 接口上报

场景说明:

你想每天定时备份 MySQL 和 MongoDB,并在完成后通过 curl 报告备份信息。

脚本:backup_and_report.sh
#!/bin/bash# 1. 定义开始时间
start_time=$(date +"%Y-%m-%d %H:%M:%S")# 2. 执行备份命令(这里用 docker 容器)
container_id=$(docker ps | grep community | awk '{print $1}')
docker exec -it "$container_id" bash -c 'source /entrypoint.sh && backup mysql mongodb file'# 3. 定义结束时间
end_time=$(date +"%Y-%m-%d %H:%M:%S")# 4. 找到最新备份路径
backup_dir="/data/mingdao/script/volume/data/backup"
latest=$(ls -td ${backup_dir}/*/ | head -n 1)# 5. 上报接口
curl -X POST http://api.example.com/backup/report \-H "Content-Type: application/json" \-d '{"startTime": "'"$start_time"'","endTime": "'"$end_time"'","backupPath": "'"$latest"'"}'
配合 crontab 每天凌晨1点执行:
0 1 * * * /bin/bash /opt/scripts/backup_and_report.sh >> /var/log/backup.log 2>&1

实战2:自动部署前端代码到远程服务器

脚本:deploy_frontend.sh
#!/bin/bashdist_dir="./dist"
remote_user="deploy"
remote_host="192.168.10.100"
remote_path="/data/www/"rsync -avz --delete "$dist_dir/" "$remote_user@$remote_host:$remote_path"
echo "部署完成:$(date)"

实战3:系统监控报警脚本

脚本:check_cpu.sh
#!/bin/bashthreshold=80
cpu_usage=$(top -bn1 | grep "Cpu(s)" | awk '{print 100 - $8}')  # $8为空闲if [ $(echo "$cpu_usage > $threshold" | bc) -eq 1 ]; thencurl -X POST http://api.example.com/alert \-H "Content-Type: application/json" \-d '{"message": "CPU使用率过高:'"$cpu_usage"'%"}'
fi

实战4:交互式菜单工具脚本

脚本:menu.sh
#!/bin/bashwhile true; doecho "====== 系统工具菜单 ======"echo "1. 查看磁盘使用"echo "2. 查看内存使用"echo "3. 查看登录用户"echo "4. 退出"read -p "请输入选项[1-4]:" choicecase $choice in1) df -h ;;2) free -h ;;3) who ;;4) echo "Bye!"; exit 0 ;;*) echo "无效输入" ;;esac
done

实战5:每日自动压缩日志

#!/bin/bashlog_dir="/var/log/myapp"
backup_dir="/data/log_backup"
today=$(date +%F)mkdir -p "$backup_dir"
tar -czf "$backup_dir/logs_$today.tar.gz" "$log_dir"/*.log
rm -f "$log_dir"/*.log

本章练习题

  1. 写一个脚本定时将 /etc 目录打包上传到远程服务器。
  2. 写一个脚本每天查找 /tmp.log 文件并清理超过3天的文件。
  3. 写一个自动监测服务器磁盘占用超过 90% 就上报告警的脚本。

第8章 · 个人实战项目总结:自动化备份 + 压缩 + 清理 + 上报


脚本目标

每天凌晨 1 点自动执行以下操作:

  1. 判断磁盘空间是否足够
  2. 执行容器内数据库+文件备份命令
  3. 将备份目录压缩为 .tar.gz
  4. 删除原始目录
  5. 保留最近 3 个压缩文件
  6. 上报接口通知备份结果
  7. 生成详细执行日志
  8. 防止多次重复执行

脚本路径

/data/backup_and_notify.sh

最终正式版脚本

#!/bin/bash
set -euo pipefail   # 脚本遇错立即退出,禁止未定义变量,管道中出错也终止
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin# ========== 配置区域 ==========
LOG_FILE="/tmp/cron_exec.log"                         # 日志文件路径
LOCK_FILE="/tmp/backup.lock"                          # 锁文件路径(防止重复执行)
BACKUP_BASE="/backup_base" # 备份目录(需确保存在)
API_URL="http://your-api-host/your/endpoint"          # 上报接口地址(请替换)
DEBUG_MODE=false                                       # 调试开关,true 为跳过 docker 执行并模拟
# =================================log() {echo "[$(date +"%F %T")] $1" >> "$LOG_FILE"  # log 函数:统一日志格式写入
}# ========== 防重入锁机制 ==========
if [ -f "$LOCK_FILE" ]; thenold_pid=$(cat "$LOCK_FILE")if ps -p "$old_pid" > /dev/null 2>&1; thenlog "已有任务执行中(PID=$old_pid),跳过本次"exit 0elselog "锁文件存在但进程不存在,清理锁文件"rm -f "$LOCK_FILE"fi
fiecho $$ > "$LOCK_FILE"  # 写入当前脚本 PID 为锁文件# ========== 主流程开始 ==========
log "=== 备份任务开始 ==="
start_time=$(date +"%Y-%m-%d %H:%M:%S")# 1. 检查磁盘剩余空间是否大于当前已用空间(防爆盘)
disk_info=$(df -k "$BACKUP_BASE" | tail -1)
used_kb=$(echo "$disk_info" | awk '{print $3}')
avail_kb=$(echo "$disk_info" | awk '{print $4}')
log "磁盘空间 - 已用: ${used_kb}KB, 可用: ${avail_kb}KB"if [ "$avail_kb" -lt $((used_kb * 1)) ]; thenlog "剩余空间不足,终止备份"rm -f "$LOCK_FILE"exit 1
fi# 2. 查找名为 community 的 docker 容器
container_id=$(docker ps | grep community | awk '{print $1}')
if [ -z "$container_id" ]; thenlog "未找到包含 community 的容器,退出"rm -f "$LOCK_FILE"exit 1
fi
log "容器 ID: $container_id"# 3. 执行备份命令或生成模拟目录
if [ "$DEBUG_MODE" == "true" ]; thenlog "[调试模式] 跳过 docker 备份,生成模拟目录"mock_dir_name=$(date +"%Y%m%d%H%M%S")mock_dir_path="$BACKUP_BASE/$mock_dir_name"mkdir -p "$mock_dir_path"echo "模拟数据文件内容" > "$mock_dir_path/mock.txt"latest_backup="$mock_dir_path"
elselog "执行容器备份命令..."docker exec "$container_id" bash -c 'source /entrypoint.sh && backup mysql mongodb file'log "容器内备份完成"latest_backup=$(ls -td "$BACKUP_BASE"/*/ 2>/dev/null | head -n 1)
fiend_time=$(date +"%Y-%m-%d %H:%M:%S")# 4. 确认最新备份目录
if [ -z "$latest_backup" ]; thenlog "未找到最新备份目录,退出"rm -f "$LOCK_FILE"exit 1
filatest_dir_name=$(basename "$latest_backup")
log "最新备份目录:$latest_backup"# 5. 压缩目录为 .tar.gz
tar_file="$BACKUP_BASE/$latest_dir_name.tar.gz"
log "压缩目录为:$tar_file"
tar -zcvf "$tar_file" -C "$BACKUP_BASE" "$latest_dir_name" >> "$LOG_FILE" 2>&1if [ -f "$tar_file" ]; thenlog "压缩成功,删除原始目录"rm -rf "$latest_backup"
elselog "压缩失败:文件未生成"
fi# 6. 上报接口,上传 tar 包路径 + 起止时间
log "开始上报接口..."
post_result=$(curl -s -o /dev/null -w "%{http_code}" -X POST "$API_URL" \-H "Content-Type: application/json" \-d '{"startTime": "'"$start_time"'","endTime": "'"$end_time"'","backupPath": "'"$tar_file"'"}')if [ "$post_result" == "200" ]; thenlog "上报成功"
elselog "上报失败,状态码:$post_result"
fi# 7. 清理旧备份,仅保留最新 3 个 tar.gz 文件
log "开始清理旧备份(保留3份)"
old_tars=$(ls -1t "$BACKUP_BASE"/*.tar.gz 2>/dev/null | tail -n +4)
for f in $old_tars; dolog "删除旧文件:$f"rm -f "$f"
donelog "=== 备份任务结束 ==="# 8. 删除锁文件
rm -f "$LOCK_FILE"

定时任务 crontab 设置

crontab -e

添加:

0 1 * * * /bin/bash /data/backup_and_notify.sh >> /var/log/backup.log 2>&1

测试方式

  1. 设置 DEBUG_MODE=true 快速走完整流程
  2. 查看日志输出:
    • /var/log/backup.log
    • /tmp/cron_exec.log
  3. 检查是否压缩 .tar.gz 成功
  4. 检查是否自动清理旧文件
  5. 检查是否触发上报接口

第9章:Shell 脚本高阶技巧与调试优化


一、调试脚本的方法

1. 手动打印变量值(最常用)
echo "当前值是:$var"
2. 使用 set -x 开启调试模式
#!/bin/bash
set -x    # 开始调试
...你的代码...
set +x    # 关闭调试

会打印出每一行执行的命令和变量展开后的值,便于追踪问题。

3. 整体调试脚本执行
bash -x yourscript.sh

二、安全与健壮性写法

1. 脚本头部加入防御设置
#!/bin/bash
set -euo pipefail
  • -e: 一旦出错立即退出
  • -u: 使用未定义变量时立即退出
  • -o pipefail: 管道中任何一个命令出错就认为整个失败
2. 变量默认值
echo "用户名:${USERNAME:-guest}"

如果 USERNAME 未定义,则默认值为 guest

3. 防止空变量导致误删
# 错误写法(rm -rf $dir,如果 $dir 是空,会删当前目录)
rm -rf "$dir"# 安全写法
if [ -n "$dir" ]; thenrm -rf "$dir"
fi

三、优化脚本结构

1. 使用函数模块化脚本
backup_mysql() { ... }
backup_mongo() { ... }
send_report() { ... }main() {backup_mysqlbackup_mongosend_report
}main
2. 拆分配置文件

将常量配置提取到 config.sh,主脚本中用 source ./config.sh 引入,方便统一维护。


四、日志管理与错误输出

记录日志
log() {echo "[$(date +"%F %T")] $1" >> /var/log/myscript.log
}
捕获错误信息
some_command 2>> error.log

五、制作可执行命令脚本

chmod +x mytool.sh
mv mytool.sh /usr/local/bin/mytool

之后你就可以在任何地方输入 mytool 直接调用脚本了。


六、实践建议与面试亮点

  • 编写脚本时,错误处理永远优先
  • 函数 + 配置分离是结构清晰的关键;
  • 使用 set -euo pipefail 保证健壮性;
  • 利用 cron + curl + shell 可构建一整套自动化任务、监控、备份系统;
  • 如果要参加面试,可主动讲你写过哪些“脚本工具”、怎么处理日志、怎么保障安全 —— 是加分项!

七、本章练习与挑战

  1. 为你最常用的命令写一个简化脚本,如批量清理日志、上传打包文件。
  2. 尝试把项目中某个手工流程自动化为脚本,比如打包部署/数据库备份。
  3. 写一个脚本框架,支持日志输出、错误捕获、配置参数、分函数执行。

相关文章:

Shell 脚本开发从入门到实战

第1章:什么是 Shell 与 Shell 脚本? 一、Shell 是什么? Shell 是一个命令解释器,是你在 Linux 里敲命令的地方。你平时用的命令如 cd、ls、echo,其实都由 Shell 来解析执行。最常见的 Shell 是 Bash,绝大…...

宇视设备视频平台EasyCVR打造智慧酒店安防体系,筑牢安全防线

一、需求背景 酒店作为人员流动频繁的场所,对安全保障与隐私保护有着极高的要求。为切实维护酒店内部公共区域的安全秩序,24小时不间断视频监控成为必要举措。通常情况下,酒店需在本地部署视频监控系统以供查看,部分连锁酒店还希…...

深度解读分销小程序商城源码系统:从搭建到运营的关键指南​​​​

在移动互联网浪潮的席卷下,电商领域持续变革与创新。分销小程序商城凭借其独特优势,如依托社交平台流量、便捷的购物体验、高效的分销推广模式等,成为众多企业和创业者开展线上业务的热门选择。深入了解分销小程序商城源码系统,从…...

BeeWorks:打造安全可控的企业内网即时通讯平台

在数字化办公时代,企业对即时通讯工具的需求日益增长,尤其是对数据安全和隐私保护有严格要求的行业,如金融、政府、医疗等。BeeWorks 作为一款专注于内网部署的即时通讯软件,凭借其卓越的安全性、稳定性、丰富的功能以及全面的信创…...

微信小程序开发:废品回收小程序-功能清单

用户端:便捷体验,触手可及 废品百科与估价指南:平台以直观的方式展示各类废品的分类标准与实时市场价格,让用户轻松掌握废品价值,决策更从容。 一键预约,轻松回收:用户只需轻触屏幕&#xff0c…...

【Grok 大模型深度解析】第一期:技术溯源与核心突破

一、Grok的技术基因:从Transformer到混合架构的演进 1.1 Transformer架构的局限性 2017年Google提出的Transformer架构彻底改变了自然语言处理领域,其自注意力机制(Self-Attention)在长序列建模上表现优异。然而,随着模型规模的增大,传统Transformer暴露出以下问题: 计…...

性能比拼: Redis vs Memcached

本内容是对知名性能评测博主 Anton Putra Redis vs Memcached Performance Benchmark 内容的翻译与整理, 有适当删减, 相关指标和结论以原作为准 在本视频中,我们将对比 Redis 和 Memcached。我会介绍一些功能上的不同,但主要关注 性能。 首先&#xf…...

Mujoco xml actuator

actuator general(通用执行器)motor(电机执行器)position(位置伺服)velocity(速度伺服)intvelocity(积分速度伺服)damper(主动阻尼器)…...

Mybatis Plus分页查询返回total为0问题

概述 最近开发公司新项目,使用 Mybatis Plus 分页,发现总数和总页数为0,在此记录问题和解决方案。 添加 MybatisPlusConfig /*** author: lanys* version: 1.0* 创建时间:2025年4月9日 14:24:40* Description: MybatisPlus分页…...

多卡分布式训练:torchrun --nproc_per_node=5

多卡分布式训练:torchrun --nproc_per_node=5 1. torchrun 实现规则 torchrun 是 PyTorch 提供的用于启动分布式训练作业的实用工具,它基于 torch.distributed 包,核心目标是简化多进程分布式训练的启动和管理。以下是其主要实现规则: 进程启动 多进程创建:torchrun 会…...

网络层-IP地址计算

例1:IP地址二进制与十进制互转 题目: 将二进制IP 11000000.10101000.00000001.00001010 转换为点分十进制。将IP地址 172.16.254.1 转换为二进制格式。 答案与解析: 转换步骤: 每个8位二进制转为十进制: 11000000 →…...

BeagleBone Black笔记

目录 参考资料开机led控制GPIO输入输出插网线联网安装gcc编译工具镜像备份验证备份完整性将内存卡插入目标BBBboot启动开关 参考资料 链接: BeagleBone Black使用(一):狗板简介 链接: 使用Beaglebone Black的IO口 开机 直接用usb连接到电脑…...

【25软考网工笔记】第一章 计算机网络概述

目录 一、计算机网络发展与分类 1. 计算机网络形成和发展 1)ICT 2)计算机网络的发展 3)我国互联网发展 2. 计算机网络分类 1)通信子网和资源子网 2)PAN、LAN、MAN、WAN 3)其他分类方式 3. 计算机…...

Soybean Admin 配置vite兼容低版本浏览器、安卓电视浏览器(飞视浏览器)

环境 window10 pnpm 8.15.4 node 8.15.4 vite 5.1.4 soybean admin: 1.0.0 native-ui: 2.38.0 小米电视 MIUI TV版本:MiTV OS 2.7.1886(稳定版) 飞视浏览器:https://www.fenxm.com/1220.html在小米电视安装飞视浏览器可以去小红书查安装教程&#xff1a…...

MicroPython 开发ESP32应用教程 之 I2S、INMP441音频录制、MAX98357A音频播放、SD卡读写

本课程我们讲解Micropython for ESP32 的i2s及其应用,比如INMP441音频录制、MAX98357A音频播放等,还有SD卡的读写。 一、硬件准备 1、支持micropython的ESP32S3开发板 2、INMP441数字全向麦克风模块 3、MAX98357A音频播放模块 4、SD卡模块 5、面包板及…...

从零到一:基于DeepSeek-R1的智能贪吃蛇开发实战

《基于DeepSeek-R1的AI驱动高性能贪吃蛇游戏开发全流程解析》 一、技术选型与环境搭建 开发工具链 • 编辑器:VSCode/Sublime(支持代码生成插件) • 运行环境:Node.js v16+(用于API调用及后端服务) • 图形库:HTML5 Canvas(网页端)或OLED驱动(单片机场景) • AI引擎…...

数据结构与算法-动态规划-区间dp,状态机dp,树形dp

3-区间 DP 介绍 通常用 (dp[i][j]) 表示区间 ([i, j]) 上的某种最优值,比如 (dp[i][j]) 可以表示从下标 (i) 到 (j) 的元素进行某种操作所得到的最大收益、最小花费等。 状态转移方程:这是区间 DP 的关键。它描述了如何从较小的区间的最优解得到较大区…...

文件内容课堂总结

Spark-Core编程 Key-Value类型: partitionBy函数根据指定Partitioner重新进行分区,默认使用HashPartitioner groupByKey函数根据key对value进行分组,有三种函数签名 reduceByKey函数将数据按相同Key对Value进行聚合,与groupByKey相…...

【树莓派Pico FreeRTOS】-任务通知

任务通知 文章目录 任务通知1、硬件准备2、软件准备3、FreeRTOS的任务通知介绍4、任务通知数据传输实例RP2040 由 Raspberry Pi 设计,具有双核 Arm Cortex-M0+ 处理器和 264KB 内部 RAM,并支持高达 16MB 的片外闪存。 广泛的灵活 I/O 选项包括 I2C、SPI 和独特的可编程 I/O (…...

c++11新内容补充

1.列表初始化 1.1传统{ }初始化 c98的{ }初始化主要是用于数组,以及结构体 1.2c11{ }初始化 1.让内置类型和自定义类型都可以用{ }实现多个数据初始化,而自定义类型的实现原理是类型转换(没优化的版本是先构造临时对象,然后拷贝构…...

动态规划基础

动态规划 动态规划概论楼梯最短路最长上升子序列(LIS)最长公共子序列(LCS)最长回文子串 概率动态规划区间动态规划石子合并括号序列石子合并(环形) 树形动态规划统计人数没有上司的舞会 背包01背包完全背包多重背包分组背包 动态规…...

导入 Excel 批量替换文件名称及扩展名

重命名的需求是多种多样的,我们一个方法或一个工具很难说完全满足 100% 的文件重命名的需求。如果我们的文件重命名的需求非常的复杂的时候,我们能否有一个万全的方法来帮我们实现呢?那今天就给大家介绍一下导入 excel 的方式批量修改文件名称…...

降低AIGC检测率的AI润色提示词模板

以下是针对降低AIGC检测率的 AI润色提示词模板,涵盖语言风格优化、逻辑重构、学术规范强化等维度,结合反检测策略设计,可直接用于DeepSeek等工具: 一、标题与摘要优化 1. 标题去AI化 提示词: 请将以下标题改写成更学…...

系统思考—提升解决动态性复杂问题能力

感谢合作伙伴的信任推荐! 客户今年的人才发展重点之一,是提升管理者应对动态性、复杂性问题的能力。 在深入交流后,系统思考作为关键能力模块,最终被纳入轮训项目——这不仅是一次培训合作,更是一场共同认知的跃迁&am…...

spring--整合Mybatis详解

整合Mybatis 步骤&#xff1a; 1.导入相关Maven依赖 junit mybatis mysql数据库连接 spring相关的 aop织入 mybatis-spring 2.编写配置文件 3.测试 回忆mybatis 还需连接数据库 导入依赖&#xff1a; <dependencies><dependency><groupId>juni…...

深入理解 HTML5 Audio:网页音频播放的新时代

在网页开发领域,音频的嵌入和播放一直是一个重要且不断演进的话题。HTML5 的出现,为网页音频播放带来了标准化的解决方案,极大地改善了开发者和用户的体验。 一、HTML5 之前的音频播放状况 在 HTML5 诞生之前,互联网上缺乏统一的网页音频播放标准。当时,大多数音频播放依…...

Cloudflare 缓存工作原理

Cloudflare 缓存是 Cloudflare 内容分发网络&#xff08;CDN&#xff09;的一个关键组成部分&#xff0c;通过在靠近用户的全球网络边缘服务器上存储和交付内容&#xff0c;显著提升网站性能。以下是关于 Cloudflare 缓存的相关内容&#xff1a; 工作原理 内容请求&#xff1a…...

【Unity3D中UI与物体可见性的判断方法】

系列文章目录 unity知识点 文章目录 系列文章目录&#x1f449;前言&#x1f449;一、判断UI的可见性1-1、第一种1-2、通过RectTransform计算可视区域1-3、滚动容器内可见性检测&#xff08;Scroll View&#xff09; &#x1f449;二、判断物体的可见性2-1、视锥体检测方法2-2…...

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(1):承上启下,继续上路

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(1):承上启下,继续上路 1、前言(1)情况说明(2)工程师的信仰2、知识点(1)普通形(ふつうけい)と思います(2)辞書形ことができます(3)Vたことがあります。(4)Vた とき & Vる とき3、单词(1)日语单词(2…...

ubuntu24.04 cmake 报错 libldap-2.5.so.0 解决办法

apt cmake有毛病 换源重新安装 wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | sudo apt-key add - sudo apt-add-repository "deb https://apt.kitware.com/ubuntu/ $(lsb_release -cs) main" sudo apt update sudo apt in…...

Mac 关闭浏览器左右滑动切换页面的问题

在使用触控板&#xff0c;操作浏览器时&#xff0c;左右滑动时&#xff0c;浏览器容易触发前进或者后退去查看历史记录。 如何关闭呢&#xff1f; 打开Mac- 系统设置-触控板 -更多手势 将轻扫切换页面设置为关&#xff0c;就可以了...

在 openEuler 24.03 (LTS) 操作系统上添加 ollama 作为系统服务的步骤

以下是在 openEuler 操作系统上添加 ollama 作为系统服务的步骤&#xff1a; 创建 systemd 服务文件 sudo vi /etc/systemd/system/ollama.service将以下内容写入服务文件&#xff08;按需修改参数&#xff09;&#xff1a; [Unit] DescriptionOllama Service Afternetwork.…...

华为昇腾服务器上查看固件、驱动和CANN版本的常用方法

Hey小伙伴们~&#x1f44b; 今天来聊聊怎么在华为昇腾服务器上查看固件、驱动和CANN版本吧&#xff01;&#x1f4bb; 这些信息对于确保你的服务器运行顺畅可是超级重要的哦&#xff01;下面就来给大家介绍几种常用的查看方法&#xff01;&#x1f447; &#x1f31f; ‌1. 查…...

击球手怎么玩·棒球1号位

以棒球运动为例&#xff0c;在棒球运动中&#xff0c;击球手&#xff08;Batter&#xff09;是进攻方的核心角色&#xff0c;负责通过击球创造得分机会。以下是结合棒球运动的详细介绍和击球技巧指南&#xff1a; 一、棒球基础规则 比赛目标 击球手需将投手&#xff08;Pitch…...

java基础多态------面试八股文

是什么是多态 类引用指向子类对象&#xff0c;并调用子类重写的方法&#xff0c;实现不同的行为 例子 class Animal {void sound() {System.out.println("动物发出声音");} }class Dog extends Animal {Overridevoid sound() {System.out.println("狗叫&…...

Python中的字典

文章目录 一、Python中的字典1. 字典的特点2. 字典的创建3. 字典的常见操作1. **访问字典中的值**2. **修改字典中的值**3. **添加键值对**4. **删除键值对**5. **检查键是否存在**6. **获取字典的长度**7. **遍历字典** 4. 字典的方法5. 嵌套字典6. 字典的优点7. 示例总结 二、…...

C++对象生命周期管理:从构造到析构的完整指南

在C开发中&#xff0c;准确掌握对象的生命周期管理是避免内存泄漏和资源竞争的关键。本文通过完整代码示例和内存布局分析&#xff0c;深入解析构造/析构顺序、继承体系、智能指针等核心机制&#xff0c;并分享实用调试技巧。 一、成员变量构造顺序&#xff1a;声明即命运 cl…...

代码随想录第14天:(二叉树)

一、找树左下角的值&#xff08;Leetcode 513&#xff09; 递归法&#xff1a; class Solution:def findBottomLeftValue(self, root: TreeNode) -> int:# 初始化最大深度为 -1&#xff0c;表示当前尚未遍历任何节点# 初始化 result 为 None&#xff0c;最终将存储最左边的…...

TCP/UDP的连接和数据发送过程详解

TCP TCP三次握手 在服务端启动好后会调用 listen() 方法&#xff0c;进入到 LISTEN 状态&#xff0c;然后静静等待客户端的连接请求到来。 而此时客户端主动调用 connect(IP地址) &#xff0c;就会向某个IP地址发起第一次握手&#xff0c;会先建立个半连接&#xff0c;发送SYN…...

2. 单词个数统计

【问题描述】 编写一个程序&#xff0c;输入一个句子&#xff0c;然后统计出这个句子当中不同的单词个数。例如&#xff0c;对于句子“one little two little three little boys"&#xff0c;总共有5个不同的单词&#xff0c;one, little, two, three, boys。 说明&…...

Js生成螺旋数组。

这段代码定义了一个名为 vetux 的函数&#xff0c;用于生成一个螺旋矩阵。螺旋矩阵是一种按照螺旋顺序填充数字的二维数组。以下是代码的详细解释&#xff1a; 函数定义 function vetux(n, m) {// 创建一个 m 行 n 列的二维数组&#xff0c;初始值为 0const a new Array(m).…...

《Vue.js组件化开发实战:从安全纵深到性能跃迁》

开篇&#xff1a;组件化开发的工业革命 当全球500强企业的核心业务系统在12.12大促中经受每秒38万次请求冲击时&#xff0c;我们突然意识到&#xff1a;现代前端组件已不再是简单的UI积木&#xff0c;而是承载业务逻辑、安全防护、性能优化的纳米级作战单元。本文将从军工级系统…...

【Git】--- 多人协作实战场景

Welcome to 9ilks Code World (๑•́ ₃ •̀๑) 个人主页: 9ilk (๑•́ ₃ •̀๑) 文章专栏&#xff1a; Git 前面我们学习了Git的所有本地仓库的相关操作:git基本操作,分支理解,版本回退,冲突解决等等。同时我们还理解了远端仓库在开发的作用以及相关操作push…...

SmolVLM2: The Smollest Video Model Ever(二)

这是对论文《SmolVLM: Redefining small and efficient multimodal models》的整理与翻译 SmolVLM&#xff1a;重新定义小型高效的多模态模型 拥抱脸、斯坦福大学 图1 小而强大&#xff1a;SmolVLM与其他最先进的小型视觉语言模型&#xff08;VLM&#xff09;的比较。图像结果来…...

如何通过前端表格控件实现自动化报表?1

背景 最近伙伴客户的项目经理遇见一个问题&#xff0c;他们在给甲方做自动化报表工具&#xff0c;项目已经基本做好了&#xff0c;但拿给最终甲方&#xff0c;业务人员不太买账&#xff0c;项目经理为此也是天天抓狂&#xff0c;没有想到合适的应对方案。 现阶段主要面临的问…...

数据库8(函数,变量)

1.数据类型 char(10):不足十个字符&#xff0c;用空格补全&#xff0c;数据定长&#xff1b;非统一字符编码&#xff0c;一个汉字要占两位char(2) nchar(10):不足十个字符&#xff0c;用空格补全&#xff0c;数据定长&#xff1b;统一字符编码&#xff0c;一个汉字占一位 nch…...

电阻式传感器(三)——电位器式传感器等效电路分析

(1)电位器式传感器的基本工作原理 将机械位移或其他可转换为位移变化的非电量转换为与其有一定函数关系的电阻变化&#xff0c;从而引起输出电压变化。 类型 基本结构 旋转型 直线型 非线性型 &#xff08;2&#xff09;电位器式传感器的等效电路分析 电位器式传感器的核…...

LangChain4j(1):初步认识Java 集成 LLM 的技术架构

LangChain 作为构建具备 LLM 能力应用的框架&#xff0c;虽在 Python 领域大放异彩&#xff0c;但 Java 开发者却只能望洋兴叹。LangChain4j 正是为解决这一困境而诞生&#xff0c;它旨在借助 LLM 的强大效能&#xff0c;增强 Java 应用&#xff0c;简化 LLM 功能在Java应用中的…...

力扣刷题——1339.分裂二叉树的最大乘积

给你一棵二叉树&#xff0c;它的根为 root 。请你删除 1 条边&#xff0c;使二叉树分裂成两棵子树&#xff0c;且它们子树和的乘积尽可能大。 由于答案可能会很大&#xff0c;请你将结果对 10^9 7 取模后再返回。 示例 1&#xff1a; 输入&#xff1a;root [1,2,3,4,5,6] 输…...

Pytest+Allure+Excel接口自动化测试框架实战

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 1. Allure 简介 简介 Allure 框架是一个灵活的、轻量级的、支持多语言的测试报告工具&#xff0c;它不仅以 Web 的方式展示了简介的测试结果&#xff0c;而且允…...