Linux脚本基础详解
一、基础知识
Linux 脚本主要是指在 Linux 系统中编写的用于自动化执行任务的脚本程序,其中最常用的便是 Bash 脚本。下面我们将从语法、使用方法和示例三个方面详细讲解 Linux 脚本。
1. 脚本简介
-
定义:Linux 脚本是一系列命令的集合,可以批量执行任务,从简单的命令组合到复杂的系统管理任务。
-
常见类型:最常见的是 Bash 脚本,此外还有其他如 sh、zsh、ksh 等,但 Bash 是目前 Linux 上最普遍使用的 shell。
2. 基本语法
2.1 脚本文件的开头
-
Shebang:每个脚本文件的第一行通常以
#!开头,后面跟上解释器的路径,例如:
#!/bin/bash
-
这样 Linux 系统就知道用哪个解释器来执行脚本。
2.2 注释
-
注释符号:使用
#来添加注释。注释不会被执行,用于说明代码含义:
# 这是一个注释,用于解释脚本内容
2.3 变量
-
定义变量:变量名一般不需要声明类型,直接赋值:
name="Linux脚本"
-
注意等号两边不能有空格。
-
引用变量:使用
$来引用变量:
echo "欢迎使用 $name"
2.4 命令执行
-
基本命令:可以在脚本中直接使用终端中的各种命令,例如
ls,cd,grep等。
2.5 控制结构
-
条件判断(if 语句):
if [ "$name" == "Linux脚本" ]; thenecho "变量匹配成功"
elseecho "变量匹配失败"
fi
[ ] 内是条件判断语法,== 用于字符串比较(注意:不同 shell 可能稍有不同)。
-
循环结构:
-
for 循环:
-
for i in {1..5}; doecho "当前数字:$i"
done
while 循环:
count=1
while [ $count -le 5 ]; doecho "计数:$count"count=$((count+1))
done
2.6 函数
-
定义和调用函数:
my_function() {echo "这是一个函数"
}my_function # 调用函数
3. 如何使用 Linux 脚本
3.1 编写脚本
-
创建文件:使用任意文本编辑器(如 Vim、Nano、VS Code 等)创建脚本文件,如
myscript.sh。 -
添加 shebang:确保文件第一行是
#!/bin/bash。 -
编写脚本内容:按需添加命令、变量和控制结构。
3.2 赋予执行权限
-
使用
chmod命令赋予脚本执行权限:
chmod +x myscript.sh
3.3 运行脚本
-
通过相对路径或绝对路径运行脚本:
./myscript.sh
4. 示例
示例 1:Hello World 脚本
#!/bin/bash
# 输出 Hello World
echo "Hello, World!"
解释:
-
第一行指定了 Bash 解释器。
-
使用
echo命令输出文本。
示例 2:文件备份脚本
#!/bin/bash
# 定义变量
source_dir="/home/user/data"
backup_dir="/home/user/backup"
date=$(date +%Y%m%d)# 创建备份目录(如果不存在)
mkdir -p "$backup_dir"# 进行备份
tar -czf "$backup_dir/backup_$date.tar.gz" "$source_dir"# 提示完成
echo "备份完成,文件存储在:$backup_dir/backup_$date.tar.gz"
解释:
-
定义了源目录和备份目录。
-
使用
date命令生成当前日期,并作为备份文件名的一部分。 -
使用
mkdir -p保证目录存在。 -
使用
tar命令进行打包压缩。
5. 注意事项
-
调试技巧:在脚本开头添加
set -x可以启用调试模式,帮助追踪脚本执行过程;使用set -e可在命令出错时立即退出脚本。 -
兼容性:不同的 Linux 发行版和 shell 版本可能存在细微差异,写脚本时尽量保证兼容性。
-
安全性:注意处理变量和用户输入,避免命令注入等安全问题。
二、逻辑运算符
在 Bash 脚本中,逻辑运算符可以用于控制命令的执行顺序或在条件表达式中组合多个条件。下面详细介绍常用的逻辑运算符及其用法。
1. 命令级别的逻辑运算符
1.1 &&(逻辑与)
-
作用:只有当前一个命令执行成功(返回值为 0)时,才会执行后面的命令。
-
示例:
# 如果文件存在则输出提示信息
[ -f "file.txt" ] && echo "file.txt 文件存在"
-
在这个示例中,只有当
[ -f "file.txt" ]判断为真(即file.txt文件存在)时,echo命令才会执行。
1.2 ||(逻辑或)
-
作用:只有当前一个命令执行失败(返回值不为 0)时,才会执行后面的命令。
-
示例:
# 如果文件不存在则输出提示信息
[ -f "file.txt" ] || echo "file.txt 文件不存在"
-
这里只有在
[ -f "file.txt" ]返回假(即文件不存在)的情况下,echo命令才会执行。
1.3 组合使用
-
常见模式:
command1 && command2 || command3
这种模式在逻辑上可以理解为:如果command1成功就执行command2,否则执行command3。
示例:
# 尝试更新软件包索引,成功则输出“更新成功”,否则输出“更新失败”
sudo apt-get update && echo "更新成功" || echo "更新失败"
-
注意:这种写法要留意短路问题,如果
command1成功但command2执行失败,那么整体逻辑会跳转到||后面的命令。
2. 条件表达式中的逻辑运算符
在条件判断中(如 if 语句),常用的逻辑运算符有 -a(与)、-o(或),以及使用 && 和 || 结合扩展的 [[ ... ]] 测试命令。
2.1 使用单中括号 [ 的逻辑运算符
-
-a:逻辑与。 -
-o:逻辑或。示例:
# 检查文件是否存在且可读
if [ -f "file.txt" -a -r "file.txt" ]; thenecho "file.txt 文件存在且可读"
elseecho "条件不满足"
fi
-
这里
-a表示两个条件都为真时,if 语句的主体才会被执行。
2.2 使用双中括号 [[ 的逻辑运算符
[[ ... ]] 是 Bash 的扩展测试命令,它支持更多的操作符,并且语法上更宽松。在 [[ ... ]] 中可以直接使用 && 和 || 来组合条件。
示例:
# 检查变量是否为特定值
value="abc"
if [[ $value == "abc" || $value == "def" ]]; thenecho "变量的值为 abc 或 def"
elseecho "变量的值不匹配"
fi
在上面的示例中,|| 用于表示两个条件只要有一个为真,就满足 if 条件。
3. 逻辑非运算符
3.1 命令级别
-
!:用于取反一个命令的返回值。示例:
# 如果命令失败,则输出提示信息
! grep "search_string" file.txt && echo "没有找到指定字符串"
-
这里
grep查找失败时返回非 0,!将其反转为真,从而执行echo命令。
3.2 条件表达式中
在 [[ ... ]] 中也可以使用 ! 来取反一个条件:
if [[ ! -d "/mydir" ]]; thenecho "/mydir 目录不存在"
fi
这个示例中,如果 /mydir 目录不存在,则条件取反为真,执行 echo。
4. 小结
-
&&与||:在命令级别控制命令执行顺序,根据前一个命令的返回状态决定后续命令是否执行。 -
条件测试中的逻辑运算符:在
[ ... ]中使用-a(与)和-o(或),在[[ ... ]]中可以直接使用&&和||,提高了表达条件的灵活性。 -
!取反运算符:既可用于命令级别也可用于条件表达式中,用于反转逻辑判断结果。
通过这些逻辑运算符,Bash 脚本可以实现更复杂、更灵活的流程控制。希望以上详细说明和示例能帮助你更好地理解和使用 Linux 脚本中的逻辑运算符。
三、函数用法
在 Bash 脚本中,函数是用来组织和复用代码的基本单元,可以将一段逻辑封装在一个函数中,方便调用和管理。下面详细讲解 Bash 脚本中的函数,包括定义、调用、参数传递、局部变量和返回值等方面。
1. 定义函数
在 Bash 中,定义函数主要有两种语法:
1.1 标准语法
直接写出函数名,后面跟上圆括号,然后用大括号包裹函数体:
my_function() {# 函数体echo "这是我的第一个函数"
}
1.2 使用 function 关键字
另一种写法是在函数名前加上 function 关键字,圆括号可以省略,但建议保留以保持风格统一:
function my_function {echo "这是使用 function 关键字定义的函数"
}
2. 调用函数
定义好函数后,只需要直接写出函数名来调用即可。例如:
#!/bin/bashmy_function() {echo "函数调用成功!"
}# 调用函数
my_function
执行脚本时,会输出 “函数调用成功!”。
3. 函数参数传递
函数在调用时可以接受参数,这些参数在函数体内通过 $1、$2 … $n 来引用,与脚本中的命令行参数类似。
示例
#!/bin/bashgreet() {name=$1echo "你好,$name!"
}greet "张三" # 调用函数,并传递参数 "张三"
在这个示例中,函数 greet 会输出 “你好,张三!”。
4. 局部变量
默认情况下,函数中的变量是全局变量,可能会影响脚本中其他部分。为了防止这种情况,可以使用 local 关键字声明局部变量,使其仅在函数内有效。
示例
#!/bin/bashchange_value() {local value=100echo "函数内部 value: $value"
}value=10
echo "调用函数前 value: $value"
change_value
echo "调用函数后 value: $value"
输出结果会显示调用函数前后的 value 值不同,说明函数内的 value 是局部变量,不影响全局变量。
5. 函数返回值
Bash 函数的返回值主要通过以下两种方式传递:
5.1 返回退出状态
使用 return 关键字返回一个整数(退出状态),一般用来表示成功(0)或失败(非0)状态。示例:
#!/bin/bashcheck_file() {if [ -f "$1" ]; thenreturn 0 # 成功:文件存在elsereturn 1 # 失败:文件不存在fi
}check_file "/etc/passwd"
if [ $? -eq 0 ]; thenecho "文件存在"
elseecho "文件不存在"
fi
在这个示例中,通过 $? 来获取函数返回的状态值。
5.2 输出结果传递
有时我们需要返回一个字符串或更复杂的数据,可以通过 echo 输出结果,然后在调用处使用命令替换(例如 result=$(my_function))来获取输出。
#!/bin/bashget_date() {# 输出当前日期echo "$(date +%Y-%m-%d)"
}current_date=$(get_date)
echo "今天的日期是:$current_date"
6. 小结
-
定义函数:使用
函数名()或function 函数名两种语法。 -
调用函数:直接写出函数名即可调用。
-
参数传递:函数参数用
$1、$2… 引用,数量不限。 -
局部变量:使用
local声明变量,防止影响全局作用域。 -
返回值:通过
return返回退出状态或使用echo输出传递结果。
通过这些机制,Bash 脚本中的函数能够帮助你实现代码模块化、复用性和更高的可维护性,从而构建出功能丰富且结构清晰的脚本。
四、命令替换与流程控制符
在 Bash 脚本中,命令替换和流程控制符是两种常用的语法机制,它们分别用于不同的场景:
1. 命令替换
定义:
命令替换允许你在另一个命令中嵌入一个命令,并将该命令的输出结果直接作为文本插入到当前位置。这种机制非常有用,比如将命令的输出赋值给变量或者作为其他命令的参数。
语法:
有两种主要写法:
-
使用反引号:
result=`命令` -
使用
$()语法(推荐):result=$(命令)
示例:
#!/bin/bash
# 使用命令替换获取当前日期,并赋值给变量 today
today=$(date +%Y-%m-%d)
echo "今天的日期是:$today"
在这个示例中,date +%Y-%m-%d 命令的输出会被替换到 $() 中,并赋值给变量 today,最终输出当前日期。
2. 流程控制符
定义:
流程控制符是一些特殊的字符或符号,用于控制多个命令的执行顺序、并行运行、管道传输等。它们帮助你组织脚本的执行流程,让脚本可以更加灵活和高效地执行任务。
常见的流程控制符:
-
分号
;:
用于在一行内分隔多个命令,使得这些命令按顺序依次执行。
echo "第一个命令"; echo "第二个命令"
-
上例中,两个
echo命令会依次执行。 -
换行符:
换行也是一种自然的流程控制符,每行一个命令。 -
管道符
|:
将一个命令的输出直接传递给下一个命令作为输入。
ls | grep "txt"
-
这里,
ls命令的输出会传递给grep命令,筛选出包含 "txt" 的行。 -
后台运行符
&:
用于将命令放到后台执行,这样不会阻塞后续命令的执行。
long_running_command &
echo "继续执行其他命令"
-
逻辑运算符
&&和||(在命令级别已在之前讨论):-
&&:当前一个命令成功时执行下一个命令。 -
||:当前一个命令失败时执行下一个命令。
-
-
命令分组符
()和{}:-
小括号
()可以将一系列命令放在一个子 Shell 中执行:
-
(cd /tmp && ls)
-
上例中,
cd /tmp和ls在一个子 Shell 中执行,改变目录的操作不会影响主 Shell。 -
大括号
{}则在当前 Shell 中执行:
{ echo "第一条命令"; echo "第二条命令"; }
小结:
-
命令替换:通过反引号或
$()语法,把一个命令的输出作为字符串替换到其他命令中,例如赋值给变量。 -
流程控制符:通过分号、管道、后台运行符、逻辑运算符和分组符等,控制命令的执行顺序、并行性以及数据流向,从而构建复杂的执行逻辑。
这两种机制配合使用,可以使 Bash 脚本既具有动态获取信息的能力,又能灵活控制任务的执行流程,从而编写出高效、功能丰富的自动化脚本。
熟悉各种 Linux 命令并能灵活组合是编写 Linux 脚本的重要基础。但仅仅了解命令还不够,掌握 Linux 脚本还需要注意以下几个方面:
-
流程控制与条件判断:如何利用 if、case、for、while 等结构来控制脚本执行流程,使脚本能够根据不同情况做出决策。
-
命令替换和管道:将一个命令的输出作为另一个命令的输入,从而实现更复杂的数据处理流程。
-
函数与代码组织:通过函数将重复或复杂的逻辑封装起来,提高脚本的可读性和可维护性。
-
错误处理与调试:利用返回值、日志输出、调试选项(如
set -x)等手段,确保脚本在出错时能够及时捕捉并做出应对。 -
变量、环境与参数传递:有效地管理脚本中的数据,包括局部变量与全局变量,以及从命令行接收参数,从而使脚本更加通用和灵活。
综上所述,掌握 Linux 脚本不仅仅是熟悉单个命令的用法,更重要的是理解如何将这些命令、控制结构和编程概念组合起来,以构建出高效、灵活且易于维护的自动化任务。
相关文章:
Linux脚本基础详解
一、基础知识 Linux 脚本主要是指在 Linux 系统中编写的用于自动化执行任务的脚本程序,其中最常用的便是 Bash 脚本。下面我们将从语法、使用方法和示例三个方面详细讲解 Linux 脚本。 1. 脚本简介 定义:Linux 脚本是一系列命令的集合,可以…...
LabVIEW 油井动液面在线监测系统
项目背景 传统油井动液面测量依赖人工现场操作,面临成本高、效率低、安全风险大等问题。尤其在偏远地区或复杂工况下,测量准确性与时效性难以保障。本系统通过LabVIEW虚拟仪器技术实现硬件与软件深度融合,为油田智能化转型提供实时连续监测解…...
泛微ECOLOGY9 解决文档中打开发票类PDF文件无内容的配置方法
解决文档中打开发票类PDF文件无内容的配置方法 情况如下: 如果OA文档中打开的PDF文件如下图这样空白的,那么可以试试下面的方法进行解决。 解决方法: 在OA安装目录中找到 ecology/WEB-INF/prop/docpreview.properties 配置文件ÿ…...
大模型RAG项目实战-知识库问答助手v1版
安装 Ollama 根据官网指导,安装对应版本即可。 下载安装指导文档: handy-ollama/docs/C1/1. Ollama 介绍.md at main datawhalechina/handy-ollama 注意:在 Windows 下安装 Ollama 后,强烈建议通过配置环境变量来修改模型存储…...
统计子矩阵
1.统计子矩阵 - 蓝桥云课 统计子矩阵 问题描述 给定一个 NM 的矩阵 A,请你统计有多少个子矩阵(最小 11,最大 NM)满足子矩阵中所有数的和不超过给定的整数 K? 输入格式 第一行包含三个整数 N,M 和 K。 …...
Vue.js 实现下载模板和导入模板、数据比对功能核心实现。
在前端开发中,数据比对是一个常见需求,尤其在资产管理等场景中。本文将基于 Vue.js 和 Element UI,通过一个简化的代码示例,展示如何实现“新建比对”和“开始比对”功能的核心部分。 一、功能简介 我们将聚焦两个核心功能&…...
C++第1讲:基础语法;通讯录管理系统
黑马程序员匠心之作|C教程从0到1入门编程,学习编程不再难_哔哩哔哩_bilibili 对应的笔记: https://github.com/AccumulateMore/CPlusPlus 标签: C&C | welcome to here 一、C初识 1.1.注释 1.2.变量 1.3.常量:记录程序中不可更改的数据 1.4.关…...
关于Spring MVC处理JSON数据集的详细说明,涵盖如何接收和发送JSON数据,包含代码示例和总结表格
以下是关于Spring MVC处理JSON数据集的详细说明,涵盖如何接收和发送JSON数据,包含代码示例和总结表格: 1. 核心机制 Spring MVC通过以下方式支持JSON数据的传输: 接收JSON数据:使用RequestBody注解将HTTP请求体中的J…...
MySQL 隐式转换与模糊匹配的索引使用分析
MySQL 隐式转换与模糊匹配的索引使用分析 MySQL服务版本字段结构索引结构查询分析int索引查询varchar 索引查询 like 匹配总结 MySQL服务版本 版本信息:Server version: 8.0.30 MySQL Community Server - GPL 字段结构 mysql> desc connection; -------------…...
DNS服务(Linux)
DNS 介绍 dns,Domain Name Server,它的作用是将域名解析为 IP 地址,或者将IP地址解析为域名。 这需要运行在三层和四层,也就是说它需要使用 TCP 或 UDP 协议,并且需要绑定端口,53。在使用时先通过 UDP 去…...
【愚公系列】《高效使用DeepSeek》058-选题策划
🌟【技术大咖愚公搬代码:全栈专家的成长之路,你关注的宝藏博主在这里!】🌟 📣开发者圈持续输出高质量干货的"愚公精神"践行者——全网百万开发者都在追更的顶级技术博主! 👉 江湖人称"愚公搬代码",用七年如一日的精神深耕技术领域,以"…...
Python高阶函数-filter
1. 基本概念 filter() 是Python内置的高阶函数,用于过滤序列中的元素。它接收一个函数和一个可迭代对象作为参数,返回一个迭代器,包含使函数返回True的所有元素。 filter(function, iterable)2. 工作原理 惰性计算:filter对象是…...
✅ Ultralytics YOLO验证(Val)时自动输出COCO指标(AP):2025最新配置与代码详解 (小白友好 + B站视频)
✅ YOLO获取COCO指标(3):验证(Val) 启用 COCO API 评估(自动输出AP指标)| 发论文必看! | Ultralytics | 小白友好 文章目录 一、问题定位二、原理分析三、解决方案与实践案例步骤 1: 触发 COCO JSON 保存步骤 2: 确保 self.is_coc…...
MySql表达式中字符串类型与整型的隐式转换
隐式转换 当运算符与不同类型的操作数一起使用时,会发生类型转换以使操作数兼容。某些转换是隐式发生的。例如,MySQL 会根据需要自动将字符串转换为数字,反之亦然。 mysql> SELECT 11;-> 2 mysql> SELECT CONCAT(2, test);-> 2…...
拍摄的婚庆视频有些DAT的视频文件打不开怎么办
3-12 现在的婚庆公司大多提供结婚的拍摄服务,或者有一些第三方公司做这方面业务,对于视频拍摄来说,有时候会遇到这样一种问题,就是拍摄下来的视频文件,然后会有一两个视频文件是损坏的,播放不了࿰…...
Zephyr与Linux核心区别及适用领域分析
一、核心定位与目标场景 特性Zephyr RTOSLinux目标领域物联网终端、实时控制系统(资源受限设备)服务器、桌面系统、复杂嵌入式设备(如路由器)典型硬件MCU(ARM Cortex-M, RISC-V),内存<1MBMP…...
图灵逆向——题一-动态数据采集
目录列表 过程分析代码实现 过程分析 第一题比较简单,直接抓包即可,没有任何反爬(好像头都不用加。。。) 代码实现 答案代码如下: """ -*- coding: utf-8 -*- File : .py author : 鲨鱼爱兜兜 T…...
【新人系列】Golang 入门(十二):指针和结构体 - 上
✍ 个人博客:https://blog.csdn.net/Newin2020?typeblog 📝 专栏地址:https://blog.csdn.net/newin2020/category_12898955.html 📣 专栏定位:为 0 基础刚入门 Golang 的小伙伴提供详细的讲解,也欢迎大佬们…...
Day20 -实例:红蓝队优秀集成式信息打点工具的配置使用
一、自动化-企业查询 ----ENScan 原理:集成企查查、爱企查、chinaz等,剑指hw/src。 1)首次使用先创建config文件 确认一下生成了 2)配置cookie 各个平台不一样,根据github作者的教程来【放入github收藏夹了】 我这…...
MySQL学习笔记五
第七章数据过滤 7.1组合WHERE子句 7.1.1AND操作符 输入: SELECT first_name, last_name, salary FROM employees WHERE salary < 4800 AND department_id 60; 输出: 说明:MySQL允许使用多个WHERE子句,可以以AND子句或OR…...
Python爬虫第5节-urllib的异常处理、链接解析及 Robots 协议分析
目录 一、处理异常 1.1 URLError 1.2 HTTPError 二、解析链接 2.1 urlparse() 2.2 urlunparse() 2.3 urlsplit() 2.4 urlunsplit() 2.5 urljoin() 2.6 urlencode() 2.7 parse_qs() 2.8 parse_qsl() 2.9 quote() 2.10 unquote() 三、分析网站Robots协议 3.1 R…...
26届Java暑期实习面经,腾讯视频一面
短链接的生成原理 如何解决短链接生成的哈希冲突问题 如何加快从短链接到原链接的重定向过程 TCP 和 UDP 协议 如何理解 TCP 是面向连接的 为什么 TCP 的握手是 3 次 IO 模式 是否有真正写过一个底层的 Socket 通信 MySQL 的事务隔离级别 MVCC 机制 什么叫服务的并行 为什么能基…...
Kafka负载均衡挑战解决
本文为 How We Solve Load Balancing Challenges in Apache Kafka 阅读笔记 kafka通过利用分区来在多个队列中分配消息来实现并行性。然而每条消息都有不同的处理负载,也具有不同的消费速率,这样就有可能负载不均衡,从而使得瓶颈、延迟问题和…...
前端性能优化的全方位方案【待进一步结合项目】
以下是前端性能优化的全方位方案,结合代码配置和最佳实践,涵盖从代码编写到部署的全流程优化: 一、代码层面优化 1. HTML结构优化 <!-- 语义化标签减少嵌套 --> <header><nav>...</nav> </header> <main&…...
2025年第二期PMP考试中文报名时间定了!
近日,官方发布了《关于2025年6月15日PMI认证考试的报名通知》。根据通知,中国大陆地区2025年第二期PMI认证考试将于6月15日举行,中文报名将于4月17日正式开始。 一、报名安排 为缓解报名高峰期的网络拥堵,本次考试将采取分地区、…...
LiT and Lean: Distilling Listwise Rerankers intoEncoder-Decoder Models
文章:ECIR 2025会议 一、动机 背景:利用LLMs强大的能力,将一个查询(query)和一组候选段落作为输入,整体考虑这些段落的相关性,并对它们进行排序。 先前的研究基础上进行扩展 [14,15],…...
【Java面试系列】Spring Boot微服务架构下的分布式事务处理与Seata框架实现原理详解 - 3-5年Java开发必备知识
【Java面试系列】Spring Boot微服务架构下的分布式事务处理与Seata框架实现原理详解 - 3-5年Java开发必备知识 1. 引言 在微服务架构中,分布式事务处理是一个不可避免的挑战。随着业务复杂度的提升,单体应用逐渐演变为微服务架构,而分布式事…...
源码分析之Leaflet图层控制控件Control.Layers实现原理
概述 本文将介绍Leaflet库中最后一个组件,即图层控制组件 Control.Layers。 源码实现 export var Layers Control.extend({options: {collapsed: true,position: "topright",autoZIndex: true,hideSingleBase: false,sortLayers: false,sortFunction:…...
嵌入式软硬件开发,常见通信总线
嵌入式通信总线分类与应用指南 一、片上/板级通信接口(内部互联) I2C总线 核心特性 同步半双工传输,SCL时钟线SDA数据线7/10位地址寻址,支持多主多从架构标准模式100kbps,高速模式3.4Mbps,超高速模式5Mbps…...
[ERROR] Some problems were encountered while processing the POMs
记录一次maven的错误 问题复现: 我在ruoyi-vue-plus项目的ruoyi-modules中新建了一个子项目ruoyi-network-telphonem,然后某一次编译的时候提示SysTenantServiceImpl找不到无参的构造函数,检查了很久都没发现问题,于是我想着删掉本地maven仓…...
