Shell脚本是一种用Shell语言编写的程序,它可以实现自动化的任务,如批量处理文件、监控系统状态、定时备份等。本文包括:
- Shell脚本的定义和作用:介绍什么是Shell脚本,它有哪些优点和缺点,它可以用来做什么。
- Shell脚本的基本语法:介绍Shell脚本的结构、变量、运算符、流程控制、函数等基本元素,给出一些简单的示例。
- Shell脚本的高级特性:介绍Shell脚本的参数传递、数组、字符串处理、正则表达式、文件操作、进程管理等高级功能,给出一些复杂的示例。
- Shell脚本的应用场景:介绍一些常见的Shell脚本的应用场景,如日志分析、数据备份、系统监控等,给出一些实际的案例。
一、shell 脚本和 shell
Shell是一种命令行解释器,用于用户与操作系统进行交互和执行命令的接口。
Shell脚本是利用Shell的功能所写的一个程序。这个程序是使用纯文本文件,将一些Shell的语法与命令(含外部命令)写在里面,搭配正则表达式、管道命令与数据流重定向等功能。(简单来说就是一系列shell命令+控制结构)
Shell脚本可以实现自动化的任务,如批量处理文件、监控系统状态、定时备份等。
Shell脚本的第一行通常是指定解释器的路径,如 #!/bin/bash ,表示使用Bash来执行脚本。Shell脚本的文件名通常以.sh为扩展名,但不是必须的。要运行Shell脚本,需要给它可执行权限,如 chmod +x test.sh ,然后使用 ./test.sh 或者 /bin/bash test.sh 来执行。
Shell有很多种类型,常见的有以下几种:
- Bourne Shell (sh):由AT&T公司的Steve Bourne开发,是Unix上的标准Shell,也是其他Shell的开发基础。它在编程方面优秀,但在用户交互方面不如其他Shell。
-
Bourne Again Shell (
bash
):由GNU组织开发,是Linux系统中的默认Shell。它保持了对sh的兼容性,同时继承了csh和ksh的优点。它是目前最流行的Shell。 - C Shell (csh):由加州伯克利大学的Bill Joy开发,其语法类似C语言。它提供了一些sh不能处理的用户交互特性,如命令补全、命令别名、历史命令替换等。但它与sh不兼容。
- Korn Shell (ksh):由AT&T Bell实验室的David Korn开发,集合了csh和sh的优点,并且与sh完全兼容。它的效率很高,其命令交互界面和编程交互界面都很好。
- Z Shell (zsh):是Linux最大的Shell之一,由Paul Falstad完成,共有84个内部命令。它兼容bash,并且提供了更多的功能和扩展。
二、Shell 脚本的基本语法
Shell脚本的基本结构如下:
-
声明解释器:每个Shell脚本的第一行都应该指定解释器。在Unix系统上,常用的解释器是bash(Bourne Again SHell)。因此,可以在脚本的第一行添加以下声明:#!/bin/bash
-
注释:Shell脚本中可以使用注释来提供对脚本的解释和说明。注释以井号(#)开头,可以单独一行或出现在代码行的末尾。
-
变量:Shell脚本中使用变量来存储和操作数据。变量名必须以字母或下划线开头,后面可以跟字母、数字或下划线。变量赋值使用等号(=),如:variable_name=value。使用变量时,需要在变量名前加上美元符号( ),如: ),如: ),如:variable_name。
-
命令执行:可以在Shell脚本中执行各种系统命令。要执行命令,只需在脚本中输入命令即可。例如,要列出当前目录的文件,可以使用ls命令:ls。
-
输入输出:Shell脚本可以从用户处接收输入,并向用户显示输出。使用read命令从用户获取输入,并使用echo命令将输出发送到标准输出。
-
条件语句:条件语句用于根据条件的结果执行不同的代码块。常用的条件语句有if语句和case语句。if语句根据条件执行或跳过代码块,case语句根据不同的模式匹配执行不同的代码块。
-
循环:Shell脚本中的循环用于重复执行一段代码。常用的循环有for循环、while循环和until循环。for循环用于遍历列表或范围,while循环和until循环在条件为真或假时执行代码块。
-
函数:Shell脚本支持函数定义和调用。函数可以帮助组织和重用代码。定义函数使用关键字function,调用函数时只需使用函数名即可。
-
参数传递:可以在Shell脚本中将参数传递给脚本或函数。脚本参数使用特殊变量$1、$2等表示,函数参数使用类似的方式。
-
文件处理:Shell脚本可以处理文件和目录。可以使用各种命令来读取、写入和操作文件。常用的文件处理命令有cat、grep、sed和awk等。
-
错误处理:Shell脚本可以捕获和处理错误。可以使用条件语句和命令返回值来检查命令是否成功执行,并采取相应的措施。
下面对上面的部分内容做详细介绍。
2.1 脚本头
每个Shell脚本都应该以#!/bin/bash
或#!/bin/sh
开头,这叫做脚本头(shebang),它告诉系统用哪种Shell来执行这个脚本。bash和sh是两种常见的Shell,它们有一些细微的差别,但大部分情况下是兼容的。
2.2 注释
注释是用来说明代码的意义或功能的文字,它不会被执行。在Shell脚本中,注释以#
开头,可以单独占一行,也可以跟在命令后面。例如:
# 这是一个注释
echo "Hello, world!" # 这也是一个注释
2.3 变量
变量是用来存储数据的标识符,它可以是数字、字符串、数组等。在Shell脚本中,变量的定义和使用都不需要加任何符号,只要把变量名和赋值符号(=)之间没有空格即可。例如:
name="Alice" # 定义一个变量name,赋值为Alice
echo $name # 使用变量name,需要加$符号
变量名可以由字母、数字和下划线组成,但不能以数字开头。变量名区分大小写,也就是说name和Name是两个不同的变量。
2.4 参数
参数是指传递给脚本或函数的数据,它们可以用特殊的变量来获取。在Shell脚本中,参数的特殊变量有以下几个:
-
$0
:表示脚本的文件名 -
$1
~$9
:表示第1到第9个参数 -
${10}
~${n}
:表示第10到第n个参数,需要加花括号 -
$*
:表示所有参数,作为一个整体 -
$@
:表示所有参数,作为一个数组 -
$#
:表示参数的个数
例如:
# 假设这个脚本叫做test.sh,并且执行时传递了三个参数a b c
echo $0 # 输出test.sh
echo $1 # 输出a
echo $2 # 输出b
echo $3 # 输出c
echo ${10} # 输出空白,因为没有第10个参数
echo $* # 输出a b c
echo $@ # 输出a b c
echo $# # 输出3
2.5 命令
命令是指执行某种操作的指令,它可以是系统内置的命令,也可以是用户自定义的命令。在Shell脚本中,命令通常以换行符或分号(;)来分隔。例如:
ls # 列出当前目录下的文件和文件夹
pwd; date # 显示当前目录和当前日期
命令可以接受参数和选项来修改其行为。参数通常跟在命令后面,选项通常以短横线(-)开头,可以有一个或多个字母。例如:
ls -l # 以长格式列出当前目录下的文件和文件夹
cp -r source destination # 复制source目录及其子目录和文件到destination目录
命令的执行结果可以用反引号(`)或美元符号和圆括号($())来捕获,然后赋值给变量或作为其他命令的参数。例如:
files=`ls` # 把ls命令的结果赋值给变量files
echo $files # 输出变量files的值
today=$(date +%Y%m%d) # 把date命令的结果赋值给变量today,使用+%Y%m%d选项来指定日期格式
echo $today # 输出变量today的值
好的,这是第二部分:
2.6 流程控制
流程控制是指根据条件或循环来控制代码的执行顺序。在Shell脚本中,常见的流程控制语句有以下几种:
- if…then…else…fi:根据条件来执行不同的代码块,条件可以用test命令或方括号([ ])来表示,需要以fi来结束。例如:
# 判断参数是否为0
if [ $1 -eq 0 ]; then
echo "Zero"
elif [ $1 -gt 0 ]; then # elif表示否则如果,可以有多个
echo "Positive"
else # else表示否则,只能有一个
echo "Negative"
fi # 结束if语句
- case…in…esac:根据参数的值来执行不同的代码块,每个代码块以右圆括号())结束,需要以esac来结束。例如:
# 根据参数的值输出不同的信息
case $1 in
start) # 如果参数为start
echo "Starting..."
;; # 双分号表示结束这个代码块
stop) # 如果参数为stop
echo "Stopping..."
;;
restart) # 如果参数为restart
echo "Restarting..."
;;
*) # 如果参数为其他值,*表示匹配任意值
echo "Invalid argument"
;;
esac # 结束case语句
- for…do…done:根据一个列表或一个范围来循环执行一段代码,需要以done来结束。例如:
# 遍历一个列表并输出每个元素
for fruit in apple banana orange; do
echo $fruit
done
# 遍历一个范围并输出每个数字,{1..10}表示从1到10,步长为1
for i in {1..10}; do
echo $i
done
# 遍历一个范围并输出每个数字,{1..10..2}表示从1到10,步长为2
for i in {1..10..2}; do
echo $i
done
# 遍历一个数组并输出每个元素,数组用小括号(())来定义,用美元符号和大括号(${})来引用
array=(red green blue)
for color in ${array[@]}; do
echo $color
done
# 遍历一个文件中的每一行并输出每一行,使用read命令来读取文件内容,使用<符号来重定向文件输入
while read line; do
echo $line
done < file.txt
# 遍历一个命令的输出结果并输出每一行,使用read命令来读取命令输出,使用<符号和反引号(`)或美元符号和圆括号($())来重定向命令输出
while read line; do
echo $line
done < `ls`
好的,这是7.函数及其剩余的内容:
2.7 函数
函数是一段可以重复使用的代码,它可以接受参数并返回值。在Shell脚本中,函数的定义和调用都不需要加任何符号,只要把函数名和花括号({})之间没有空格即可。例如:
# 定义一个函数,名为greet,接受一个参数,表示名字
greet() {
echo "Hello, $1!" # 输出问候语,$1表示第一个参数
}
# 调用函数,传递一个参数,表示名字
greet Bob # 输出Hello, Bob!
greet Alice # 输出Hello, Alice!
函数可以返回一个数字值,表示执行的状态或结果。返回值可以用return命令来指定,也可以用函数的最后一条命令的执行结果来表示。返回值可以用特殊变量$?
来获取。例如:
# 定义一个函数,名为add,接受两个参数,表示两个数字
add() {
return $(($1 + $2)) # 返回两个参数的和,使用$(( ))来进行算术运算
}
# 调用函数,传递两个参数,表示两个数字
add 3 5 # 返回8
echo $? # 输出8
add 10 20 # 返回30
echo $? # 输出30
函数可以嵌套定义和调用,也就是说,在一个函数中可以定义和调用另一个函数。例如:
# 定义一个函数,名为square,接受一个参数,表示一个数字
square() {
return $(($1 * $1)) # 返回参数的平方
}
# 定义一个函数,名为sum_of_squares,接受两个参数,表示两个数字
sum_of_squares() {
square $1 # 调用square函数,传递第一个参数
a=$? # 把返回值赋值给变量a
square $2 # 调用square函数,传递第二个参数
b=$? # 把返回值赋值给变量b
return $(($a + $b)) # 返回两个平方的和
}
# 调用函数,传递两个参数,表示两个数字
sum_of_squares 3 4 # 返回25
echo $? # 输出25
sum_of_squares 5 6 # 返回61
echo $? # 输出61
2.8 脚本示例
#!/bin/bash
# 这是一个示例Shell脚本
# 变量示例
name="John"
age=25
# 输出变量
echo "My name is $name and I am $age years old."
# 输入示例
echo "Please enter your name:"
read input_name
echo "Hello, $input_name!"
# 条件语句示例
if [ $age -ge 18 ]; then
echo "You are an adult."
else
echo "You are a minor."
fi
# 循环示例
echo "Counting from 1 to 5:"
for ((i=1; i<=5; i++)); do
echo $i
done
# 函数示例
say_hello() {
echo "Hello, $1!"
}
say_hello "Alice"
say_hello "Bob"
# 参数传递示例
echo "Script name: $0"
echo "First argument: $1"
echo "Second argument: $2"
# 文件处理示例
echo "Contents of the current directory:"
ls
echo "Searching for 'example' in files:"
grep -r "example" .
执行:
三、Shell 脚本的高级特性
Shell 脚本除了基本的语法外,还有一些高级的特性,可以让你的脚本更强大、灵活和易用。
3.1 数组
数组是一种存储多个值的变量,它可以用小括号(()
)来定义,用美元符号和大括号(${}
)来引用。数组中的每个元素都有一个索引,从0开始。例如:
# 定义一个数组,名为colors,包含三个元素
colors=(red green blue)
# 引用数组中的第一个元素,索引为0
echo ${colors[0]} # 输出red
# 引用数组中的最后一个元素,索引为-1
echo ${colors[-1]} # 输出blue
# 引用数组中的所有元素,使用@或*符号
echo ${colors[@]} # 输出red green blue
echo ${colors[*]} # 输出red green blue
# 引用数组中的部分元素,使用:和数字来指定范围,格式为${array[@]:start:length}
echo ${colors[@]:0:2} # 输出red green
echo ${colors[@]:1:2} # 输出green blue
# 获取数组的长度,使用#符号
echo ${#colors[@]} # 输出3
数组可以修改、添加或删除元素,也可以拼接或切割。例如:
# 修改数组中的第二个元素,索引为1
colors[1]="yellow" # 把green改为yellow
echo ${colors[@]} # 输出red yellow blue
# 添加元素到数组的末尾,使用+=运算符
colors+=("black" "white") # 添加black和white到数组末尾
echo ${colors[@]} # 输出red yellow blue black white
# 删除数组中的第三个元素,索引为2
unset colors[2] # 删除blue
echo ${colors[@]} # 输出red yellow black white
# 拼接两个数组,使用+=运算符
numbers=(1 2 3)
colors+=(${numbers[@]}) # 把numbers数组拼接到colors数组后面
echo ${colors[@]} # 输出red yellow black white 1 2 3
# 切割一个数组,使用:和数字来指定范围,格式为${array[@]:start:length}
first_three=(${colors[@]:0:3}) # 切割出前三个元素
echo ${first_three[@]} # 输出red yellow black
last_three=(${colors[@]:-3:3}) # 切割出后三个元素
echo ${last_three[@]} # 输出1 2 3
3.2 关联数组
关联数组是一种存储键值对的变量,它可以用declare -A
命令来定义,用美元符号和大括号(${}
)来引用。关联数组中的每个元素都有一个键和一个值,键可以是任意字符串。例如:
# 定义一个关联数组,名为users,包含三个键值对
declare -A users
users=([Alice]=20 [Bob]=25 [Cathy]=30)
# 引用关联数组中的某个值,使用键名
echo ${users[Alice]} # 输出20
# 引用关联数组中的所有键,使用!符号
echo ${!users[@]} # 输出Alice Bob Cathy
# 引用关联数组中的所有值,使用@或*符号
echo ${users[@]} # 输出20 25 30
echo ${users[*]} # 输出20 25 30
# 获取关联数组的长度,使用#符号
echo ${#users[@]} # 输出3
关联数组可以修改、添加或删除元素,也可以遍历或排序。例如:
# 修改关联数组中的某个值,使用键名
users[Alice]=21 # 把Alice的值改为21
echo ${users[Alice]} # 输出21
# 添加元素到关联数组中,使用键名和赋值符号(=)
users[David]=35 # 添加David和35到关联数组中
echo ${users[David]} # 输出35
# 删除关联数组中的某个元素,使用unset命令和键名
unset users[Bob] # 删除Bob和其对应的值
echo ${!users[@]} # 输出Alice Cathy David
# 遍历关联数组中的所有元素,使用for循环和!符号
for name in ${!users[@]}; do # 遍历所有的键名
echo "$name is ${users[$name]} years old" # 输出键名和对应的值
done
# 排序关联数组中的所有元素,使用sort命令和管道符号(|)
echo ${!users[@]} | sort # 按照键名排序并输出
echo ${users[@]} | sort -n # 按照值排序并输出,使用-n选项表示按照数字排序
3.3 字符串操作
字符串是一种存储文本的变量,它可以用双引号(")或单引号(')来定义,用美元符号和大括号(${})来引用。字符串可以进行一些操作,如拼接、截取、替换、匹配等。例如:
# 定义一个字符串,名为greeting,赋值为Hello, world!
greeting="Hello, world!"
# 引用字符串的值,不需要加任何符号
echo $greeting # 输出Hello, world!
# 拼接字符串,使用+运算符或直接相连
name="Alice"
message=$greeting+$name # 使用+运算符拼接字符串
echo $message # 输出Hello, world!+Alice
message=$greeting$name # 直接相连拼接字符串
echo $message # 输出Hello, world!Alice
# 截取字符串,使用:和数字来指定范围,格式为${string:start:length}
echo ${greeting:0:5} # 截取前五个字符并输出,输出Hello
echo ${greeting:7:5} # 截取第七个到第十一个字符并输出,输出world
echo ${greeting: -1} # 截取最后一个字符并输出,输出!
# 替换字符串,使用/和模式来指定替换规则,格式为${string/pattern/replacement}
echo ${greeting/world/China} # 把world替换为China并输出,输出Hello, China!
echo ${greeting//o/O} # 把所有的o替换为O并输出,输出HellO, wOrld!
# 匹配字符串,使用#或%和模式来指定匹配规则,格式为${string#pattern}或${string%pattern}
file="test.sh"
echo ${file#*.} # 从左边开始匹配第一个.及其左边的内容,并删除,输出sh
echo ${file##*.} # 从左边开始匹配最后一个.及其左边的内容,并删除,输出sh
echo ${file%.*} # 从右边开始匹配第一个.及其右边的内容,并删除,输出test
echo ${file%%.*} # 从右边开始匹配最后一个.及其右边的内容,并删除,输出test
3.4 正则表达式
正则表达式是一种用来描述文本模式的语法,它可以用来进行字符串的匹配、替换、分割等操作。在Shell 脚本中,正则表达式可以用双方括号([[ ]]
)或=~
运算符来表示。正则表达式有一些特殊的符号,如:
-
^
:表示匹配开头 -
$
:表示匹配结尾 -
.
:表示匹配任意字符 -
*
:表示匹配零个或多个前面的字符 -
+
:表示匹配一个或多个前面的字符 -
?
:表示匹配零个或一个前面的字符 -
[]
:表示匹配方括号中的任意字符 -
[^]
:表示匹配方括号中的以外的任意字符 -
()
:表示分组 -
|
:表示或者 -
\
:表示转义
例如:
# 定义一个字符串,名为text,赋值为This is a test.
text="This is a test."
# 使用双方括号和正则表达式来判断字符串是否匹配某个模式,如果匹配,返回0,否则返回1
[[ $text =~ ^This ]] # 判断字符串是否以This开头,返回0
[[ $text =~ test$ ]] # 判断字符串是否以test结尾,返回0
[[ $text =~ [a-z]+ ]] # 判断字符串是否包含一个或多个小写字母,返回0
[[ $text =~ [0-9]+ ]] # 判断字符串是否包含一个或多个数字,返回1
# 使用=~运算符和正则表达式来判断字符串是否匹配某个模式,如果匹配,返回0,否则返回1
[[ $text =~ "is" ]] # 判断字符串是否包含is,返回0
[[ $text =~ "is$" ]] # 判断字符串是否以is结尾,返回1
# 使用=~运算符和正则表达式来提取字符串中的某个部分,使用BASH_REMATCH变量来获取匹配结果
[[ $text =~ ([a-z]+)\. ]] # 判断字符串是否包含一个或多个小写字母后跟一个点,并提取小写字母部分
echo ${BASH_REMATCH[0]} # 输出test.
echo ${BASH_REMATCH[1]} # 输出test
# 使用sed命令和正则表达式来替换字符串中的某个部分,使用s命令和/符号来指定替换规则,格式为sed 's/pattern/replacement/'
echo $text | sed 's/test/example/' # 把test替换为example并输出,输出This is a example.
echo $text | sed 's/[a-z]/X/g' # 把所有的小写字母替换为X并输出,输出XXXX XX X XXXX.
# 使用grep命令和正则表达式来搜索文件中的某个模式,使用-E选项来启用扩展的正则表达式
grep -E '^[A-Z]' file.txt # 搜索文件中以大写字母开头的行并输出
grep -E '[0-9]+$' file.txt # 搜索文件中以数字结尾的行并输出
# 使用awk命令和正则表达式来处理文本数据,使用~运算符来指定匹配规则,使用$符号和数字来引用字段
awk '$1 ~ /^[A-Z]/ {print $1}' file.txt # 输出文件中第一个字段以大写字母开头的行的第一个字段
awk '$2 ~ /is/ {print $2}' file.txt # 输出文件中第二个字段包含is的行的第二个字段
3.5 信号和陷阱
信号是一种用来通知进程发生了某种事件的机制,它可以由用户、系统或其他进程发送。在Shell 脚本中,可以用kill命令或Ctrl+C等快捷键来发送信号。信号有一些预定义的名称和编号,如:
- SIGINT:表示中断信号,编号为2,可以用Ctrl+C来发送
- SIGTERM:表示终止信号,编号为15,可以用kill命令来发送
- SIGKILL:表示强制终止信号,编号为9,可以用kill -9命令来发送
- SIGQUIT:表示退出信号,编号为3,可以用Ctrl+\来发送
- SIGSTOP:表示停止信号,编号为19,可以用kill -19命令来发送
- SIGCONT:表示继续信号,编号为18,可以用kill -18命令来发送
陷阱是一种用来捕获并处理信号的机制,它可以用trap命令来定义。trap命令的格式为trap ‘action’ signal,其中action表示要执行的操作,signal表示要捕获的信号。例如:
# 定义一个陷阱,当收到SIGINT或SIGTERM信号时,输出一条信息并退出
trap 'echo "Bye bye!" && exit' SIGINT SIGTERM
# 定义一个陷阱,当收到SIGQUIT信号时,忽略该信号
trap '' SIGQUIT
# 定义一个陷阱,当收到SIGSTOP或SIGCONT信号时,执行一个函数
trap 'myfunc' SIGSTOP SIGCONT
# 定义一个函数,名为myfunc,输出一条信息
myfunc() {
echo "Hello, world!"
}
3.6 调试和错误处理
调试是一种用来检查和修复代码错误的过程,在Shell 脚本中,可以使用set命令和-x选项来启用调试模式,这样可以显示每条命令的执行过程和结果。例如:
# 启用调试模式
set -x
# 执行一些命令
echo "Hello, world!"
name="Alice"
echo $name
# 关闭调试模式
set +x
错误处理是一种用来处理代码异常的机制,在Shell 脚本中,可以使用set命令和-e选项来启用错误处理模式,这样可以让脚本在遇到错误时自动退出。例如:
# 启用错误处理模式
set -e
# 执行一些命令
echo "Hello, world!"
name="Alice"
echo $name
# 执行一个错误的命令
ls /not/exist # 这会导致脚本退出,并显示错误信息
四、Shell 脚本的应用场景
4.1 系统管理
系统管理是指对系统的配置、维护、监控等操作,Shell 脚本可以用来实现一些常见的系统管理任务,如:
- 备份和恢复数据,使用tar、cp、rsync等命令
- 安装和卸载软件,使用apt、yum、dpkg等命令
- 管理用户和权限,使用useradd、userdel、chmod等命令
- 监控系统状态和性能,使用top、ps、vmstat等命令
- 定时执行任务,使用crontab、at等命令
4.2 数据分析
数据分析是指对数据的收集、处理、分析和展示等操作,Shell 脚本可以用来实现一些简单的数据分析任务,如:
- 下载和解压数据,使用curl、wget、unzip等命令
- 清洗和转换数据,使用sed、awk、cut等命令
- 统计和计算数据,使用sort、uniq、wc等命令
- 可视化和报告数据,使用gnuplot、Rscript等命令
4.3 测试和调试
测试和调试是指对代码的检查和修复等操作,Shell 脚本可以用来实现一些测试和调试任务,如:
- 运行和停止程序,使用./、kill等命令
- 检查和修改程序输出,使用echo、read等命令
- 模拟和捕获程序输入,使用cat、tee等命令
- 跟踪和分析程序错误,使用set、trap等命令
4.4 网络通信
网络通信是指通过网络进行数据的传输和交换等操作,Shell 脚本可以用来实现一些网络通信任务,如:文章来源:https://www.toymoban.com/news/detail-527944.html
- 发送和接收邮件,使用mail、mutt等命令
- 上传和下载文件,使用ftp、scp等命令
- 浏览和爬取网页,使用curl、wget等命令
- 远程登录和控制,使用ssh、telnet等命令
把 永 远 爱 你 写 进 诗 的 结 尾 ~ 文章来源地址https://www.toymoban.com/news/detail-527944.html
到了这里,关于【Linux】shell脚本: 基本语法 和 高级特性的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!