05-流程控制之case
为什么学case语句
在Bash编程中,学习case
语句是很有必要的,主要有以下几个原因:
实现多分支逻辑
- 在Bash脚本中,经常需要根据不同的条件执行不同的操作。
case
语句提供了一种清晰、简洁的方式来处理多分支逻辑,比使用多个if-else
语句更加直观和易读。例如,根据用户输入的不同选项来执行不同的命令或函数:read -p "请输入选项(1、2或3):" choice case $choice in 1) echo "你选择了选项1" # 在这里添加选项1要执行的命令或函数 ;; 2) echo "你选择了选项2" # 在这里添加选项2要执行的命令或函数 ;; 3) echo "你选择了选项3" # 在这里添加选项3要执行的命令或函数 ;; *) echo "无效的选项" ;; esac
getopts命令
getopts
是Unix和类Unix系统中用于处理命令行参数的命令,通常在Shell脚本中使用,以下是关于它的详细介绍:
基本语法
getopts optstring name [arg]
optstring
:定义了合法的选项字符。如果选项字符后面跟有冒号:
,表示该选项需要有一个参数。例如,ab:c
表示合法的选项有a
、b
和c
,其中b
选项需要有一个参数。name
:用于在脚本中存储当前选项的变量名。在脚本中,可以通过这个变量来获取当前处理的选项字符。arg
:通常是$@
,表示传递给脚本的所有参数。如果省略arg
,则getopts
会默认使用$*
。
工作原理
getopts
命令会逐个处理命令行参数中的选项。它会在optstring
中查找与命令行选项匹配的字符,并根据其规则进行处理。对于每个选项,getopts
会将选项字符存储到指定的变量name
中,并根据选项是否需要参数进行相应的操作。如果选项需要参数,getopts
会将参数存储到特殊变量OPTARG
中。当所有选项都处理完毕后,getopts
会返回一个非零值,表示处理结束。
示例
以下是一个简单的Shell脚本示例,演示了如何使用getopts
处理命令行参数:
#!/bin/bash
while getopts "ab:c" opt; do
case $opt in
a)
echo "选项a被设置"
;;
b)
echo "选项b被设置,参数为:$OPTARG"
;;
c)
echo "选项c被设置"
;;
\?)
echo "无效的选项:-$OPTARG" >&2
exit 1
;;
esac
done
在上述脚本中,while
循环使用getopts
处理命令行参数。getopts
的optstring
为"ab:c"
,表示支持a
、b
、c
三个选项,其中b
选项需要一个参数。在case
语句中,根据不同的选项进行相应的处理。如果遇到无效的选项,会输出错误信息并退出脚本。
你可以使用以下方式调用这个脚本:
./test.sh -a -b hello -c
输出结果为:
选项a被设置
选项b被设置,参数为:hello
选项c被设置
常见用途
- 实现命令行工具的选项解析:在编写命令行工具时,
getopts
可以用于解析用户输入的各种选项,从而实现不同的功能。例如,一个文件处理工具可能支持-f
选项用于指定输入文件,-o
选项用于指定输出文件等。 - 配置脚本的参数处理:在一些需要配置参数的脚本中,
getopts
可以用于处理用户通过命令行传递的配置参数。比如,一个服务器启动脚本可能支持-p
选项用于指定端口号,-c
选项用于指定配置文件路径等。
处理命令行参数
当编写需要接受命令行参数的脚本时,case
语句可以方便地对不同的参数进行处理。例如,一个脚本可能有不同的操作模式,通过命令行参数来指定,使用case
语句可以很容易地实现根据不同参数执行相应的操作。
while getopts
:
getopts
是用来解析命令行选项的 Bash 内置命令。"a:b:c:"
表示脚本支持-a
、-b
和-c
选项,每个选项后面都需要一个参数(因为冒号:
表示需要参数)。
循环解析选项:
while getopts
会按顺序解析命令行输入的选项和参数。- 变量
$opt
会存储当前选项的名称。 $OPTARG
用于存储当前选项的参数值。
case
分支:
- 针对不同的选项 (
a
,b
,c
) 执行对应的处理逻辑,输出其参数值。 \?
匹配无效选项,输出错误信息并以状态码1
退出脚本。
#!/bin/bash
show_help() {
echo "用法: $0 [-a 参数] [-b 参数] [-c 参数]"
echo "选项:"
echo " -a 设置参数 a"
echo " -b 设置参数 b"
echo " -c 设置参数 c"
echo " -h 显示帮助信息"
}
while getopts "a:b:c:h" opt; do
echo "程序开始.."
case $opt in
a)
if [ -z "$OPTARG" ]; then
echo "错误:选项 -a 需要一个参数" >&2
exit 1
fi
echo "选项a的值为:$OPTARG"
;;
b)
if [ -z "$OPTARG" ]; then
echo "错误:选项 -b 需要一个参数" >&2
exit 1
fi
echo "选项b的值为:$OPTARG"
;;
c)
if [ -z "$OPTARG" ]; then
echo "错误:选项 -c 需要一个参数" >&2
exit 1
fi
echo "选项c的值为:$OPTARG"
;;
h)
show_help
exit 0
;;
\?)
echo "错误:无效的选项 -$OPTARG" >&2
show_help
exit 1
;;
esac
done
提高脚本的可维护性和可读性
- 对于复杂的逻辑流程,使用
case
语句可以将不同的情况分组并清晰地展示出来。这样,当其他人阅读或维护脚本时,能够快速理解脚本的功能和逻辑结构。比如,在一个系统管理脚本中,根据不同的操作类型来执行相应的系统命令,使用case
语句可以使代码结构更加清晰,易于维护。operation=$1 case $operation in "start") systemctl start httpd ;; "stop") systemctl stop httpd ;; "restart") systemctl restart httpd ;; *) echo "无效的操作。请使用start、stop或restart。" ;; esac
与其他语言特性配合
- Bash中的
case
语句可以与其他语言特性,如函数、变量、循环等结合使用,形成更强大、更灵活的脚本。例如,可以在函数中使用case
语句来根据不同的条件返回不同的值,或者在循环中使用case
语句来处理不同类型的元素。
总之,case
语句是Bash编程中的一个重要工具,它能够帮助开发者更高效地处理多分支逻辑,提高脚本的质量和可维护性,是编写复杂Bash脚本不可或缺的一部分。
1.case语句作用
case和if一样,都是用于处理多分支的条件判断
但是在条件较多的情况,if嵌套太多就不够简洁了
case语句就更简洁和规范了
2.case用法参考
常见用法就是如根据用户输入的参数来匹配,执行不同的操作。
最常见的就是如服务脚本的 {start|restart|stop|reload} 这样的操作判断
3.case基本语法
在Bash中,case
语句的基本语法如下:
case 变量 in
模式1)
# 当变量匹配模式1时执行的命令
;;
模式2)
# 当变量匹配模式2时执行的命令
;;
...
模式n)
# 当变量匹配模式n时执行的命令
;;
*)
# 当变量不匹配任何上述模式时执行的命令
;;
esac
解释说明:
case
关键字:表示开始一个case
语句。变量
:通常是一个变量或表达式,其值将与下面列出的各个模式进行比较。in
关键字:用于分隔要比较的变量和模式列表。模式1)... ;;
:这是一个模式匹配的单元。模式1
:可以是一个具体的值、一个通配符表达式或者是一个正则表达式。)
:表示模式的结束。# 当变量匹配模式1时执行的命令
:这里是当变量匹配该模式时要执行的一系列Bash命令。;;
:表示该模式匹配的命令执行结束,类似于其他语言中的break
,表示终止当前分支的执行,防止继续匹配后续模式。
*)... ;;
:这是一个特殊的模式,它匹配任何不匹配上述模式的情况,类似于default
语句在其他语言中的作用。esac
:表示case
语句的结束,是case
的反写。
模式匹配规则:
- 具体值:如果模式是一个具体的值,变量必须完全等于该值才能匹配,例如
case $var in "value")...
。 - 通配符:
*
:匹配任意字符序列,可用于匹配多个字符。例如case $var in "prefix*")...
可以匹配以prefix
开头的任何字符串。?
:匹配单个任意字符。例如case $var in "prefix?")...
可以匹配prefixa
、prefixb
等。[abc]
:匹配a
、b
或c
中的任意一个字符。例如case $var in "[abc]")...
可以匹配a
、b
或c
。[a-z]
:匹配a
到z
之间的任意一个字符。例如case $var in "[a-z]")...
可以匹配a
到z
之间的任意一个小写字母。
示例代码:
fruit="apple"
case $fruit in
"apple")
echo "This is an apple."
;;
"banana")
echo "This is a banana."
;;
"cherry")
echo "This is a cherry."
;;
*)
echo "This is some other fruit."
;;
esac
代码解释:
- 上述代码中,变量
fruit
的值为"apple"
。 - 程序将
fruit
的值依次与"apple"
、"banana"
、"cherry"
进行比较。 - 当
fruit
的值为"apple"
时,匹配第一个模式,执行echo "This is an apple."
并使用;;
终止该分支。 - 如果
fruit
的值为"banana"
或"cherry"
,会分别执行相应分支的echo
语句。 - 如果
fruit
的值不是上述三种水果,将匹配*)
模式,执行echo "This is some other fruit."
。
注意事项:
- 确保每个模式分支都以
;;
结尾,以避免执行后续的模式分支。 - 模式可以使用简单的字符串匹配或更复杂的通配符,但要注意通配符的使用范围,避免匹配到意外的结果。
- 在复杂脚本中,合理使用
case
语句可以提高代码的可读性和可维护性,避免过多的if-else
语句造成的混乱。
4.if和case的区别实践
以下是 if
和 case
在 Bash 中的区别实践:
1. 语法结构
- if 语句:
if [ 条件表达式1 ]; then # 条件表达式1 为真时执行的命令 elif [ 条件表达式2 ]; then # 条件表达式2 为真时执行的命令 elif [ 条件表达式3 ]; then # 条件表达式3 为真时执行的命令 else # 以上条件都不满足时执行的命令 fi
- case 语句:
case 变量 in 模式1) # 变量匹配模式1时执行的命令 ;; 模式2) # 变量匹配模式2时执行的命令 ;; *) # 变量不匹配任何模式时执行的命令 ;; esac
2. 适用场景
- if 语句:
- 适用于检查简单或复杂的条件,例如文件是否存在、变量是否为空、数字大小比较等。
- 可以使用逻辑运算符(如
&&
、||
、!
)来组合多个条件。 - 适合对条件进行范围检查或进行逻辑计算后的条件判断。
上述代码中,首先检查文件if [ -f "file.txt" ] && [ -r "file.txt" ]; then echo "文件存在且可读" elif [ -f "file.txt" ] && [! -r "file.txt" ]; then echo "文件存在但不可读" else echo "文件不存在" fi
file.txt
是否存在且可读,然后检查文件是否存在但不可读,最后处理文件不存在的情况。
- case 语句:
- 适用于对变量的不同取值进行判断,特别是当变量可能有多个离散的取值时。
- 对于处理命令行参数或用户输入的选项非常方便。
- 模式匹配更直观,适用于检查变量是否等于某个特定值或匹配某种模式。
上述代码中,根据用户输入的不同选项(start、stop、restart)执行不同的操作,使用read -p "请输入选项 (start|stop|restart): " option case $option in start) echo "启动服务" ;; stop) echo "停止服务" ;; restart) echo "重启服务" ;; *) echo "无效的选项" ;; esac
case
可以清晰地列出不同的选项及其对应的操作。
3. 性能考虑
- if 语句:
- 对于多个
if-elif-else
语句,可能会对同一个条件进行多次检查,尤其是在复杂的逻辑组合中。 - 性能可能会受到复杂条件表达式和逻辑运算符的影响。
- 适用于少量的、复杂的条件判断,例如需要同时考虑文件权限、大小、修改时间等多个维度的情况。
- 对于多个
- case 语句:
- 对于多个离散的选项,性能通常较好,因为只需要一次匹配操作。
- 更简洁和易读,尤其在处理用户输入或命令行参数时,只需要将输入与不同的模式匹配一次。
4. 可维护性
- if 语句:
- 对于多个
if-elif-else
语句,代码可能会变得冗长和难以阅读,特别是当条件复杂时。 - 维护时需要仔细分析逻辑表达式和运算符,以确保逻辑正确。
- 适合需要复杂逻辑判断和条件组合的情况,但可能会使代码结构较复杂。
- 对于多个
- case 语句:
- 对于处理多个离散选项,代码结构更清晰,易于阅读和维护。
- 可以方便地添加、删除或修改模式及其对应的操作,而不影响其他部分。
5. 灵活性
- if 语句:
- 可以处理更广泛的条件,包括文件测试、变量测试、算术比较等。
- 可根据不同的环境变量或文件属性做出不同的决策。
上述代码使用算术比较来判断两个变量的大小关系。if (( $a > $b )); then echo "$a 大于 $b" elif (( $a < $b )); then echo "$a 小于 $b" else echo "$a 等于 $b" fi
- case 语句:
- 更侧重于字符串匹配和模式匹配。
- 对于处理字符串类型的变量或命令行参数,提供更简洁的模式匹配功能。
上述代码使用模式匹配来判断字符串的特征。str="abc" case $str in a*) echo "以 a 开头" ;; *c) echo "以 c 结尾" ;; *) echo "其他情况" ;; esac
在实际使用中,根据具体的需求和场景选择 if
或 case
语句:
- 当需要处理多个范围条件、文件属性检查或复杂逻辑时,使用
if
语句。 - 当需要处理离散的选项、字符串匹配或用户输入时,使用
case
语句。
总之,合理使用 if
和 case
语句可以使你的 Bash 脚本更加清晰、高效和易于维护。
4.1 脚本需求
根据用户选择执行不同的操作
4.2 if写法
#!/bin/bash
echo -e "-------
1. 取钱
2. 存钱
3. 查余额
-----"
read -p "请输入你的操作:" num
if [ $num -eq 1 ];then
echo "取了5万"
elif [ $num -eq 2 ];then
echo "存了10万"
elif [ $num -eq 3 ];then
echo "余额还剩下60万"
else
echo "能不能长点心,按照要求输入?"
fi
4.3 case写法
- 明显的,if多条件判断,会存在重复性的代码,case简化了操作
- 而且还省去了出现if条件判断语法,导致的各种异常
#!/bin/bash
echo -e "-------
1. 取钱
2. 存钱
3. 查余额
-----"
read -p "请输入你的操作:" num
case $num in
1)
echo "取了5万"
;;
2)
echo "存了10万"
;;
3)
echo "余额还剩下60万"
;;
*)
echo "能不能长点心,按照要求输入?"
esac
5.使用case写出更健壮的计算器
需求(也是开发脚本的功能思路,在你很熟练语法之后,你看到这样的需求,心中应该理解想到,用哪些shell脚本的语法即可完成。)
1. 交互式接收用户输入的数字,计算符号
2. 判断用户输入的参数是否是3个
3. 判断用户输入的是否是纯数字整数
4. 判断用户输入的计算符号是否是 加减乘除
5. 如果用户输入错误,友好提示用户正确输入的语法
6. 如果输入错误,程序无须结束,循环重来让用户输入(循环知识点,以后做)
7. 重复性的代码,封装为函数(以后做)
代码
#!/bin/bash
# 数字1
read -p "请输入要计算的数字1:" num1
is_num=$(echo $num1 | sed -r "s#[0-9]+##g")
# 如果字符串非空,也就是并非纯数字
if [ ! -z $is_num ];then
echo "请输入纯数字整数!!"
exit 1
fi
# 66
# 数字2
read -p "请输入要计算的数字2:" num2
is_num=$(echo $num2 | sed -r "s#[0-9]+##g")
# 如果字符串非空,也就是并非纯数字
if [ ! -z $is_num ];then
echo "请输入纯数字整数!!"
exit
fi
echo -e "请选择运算符号:
1. +
2. -
3. *
4. /"
read -p "请输入您的符号选择:" sign
case $sign in
1)
echo "$num1 + $num2 = $(( $num1 + $num2 ))"
;;
2)
echo "$num1 - $num2 = $(( $num1 - $num2 ))"
;;
3)
echo "$num1 * $num2 = $(( $num1 * $num2 ))"
;;
4)
echo "$num1 / $num2 = $(( $num1 / $num2 ))"
;;
*)
echo "请您输入 1~4的选项。"
esac
参考答案-1
read命令解释
read -p "请输入表达式(格式:数字 运算符 数字): " input
:read
是一个命令,用于从标准输入读取用户输入的数据。-p "请输入表达式(格式:数字 运算符 数字): "
是read
命令的一个选项,它会在读取输入之前显示指定的提示信息,即"请输入表达式(格式:数字 运算符 数字): "
。input
是用户输入的数据将被存储的变量名。用户输入的内容会被存储在input
变量中。
IFS=' ' read -ra parts <<< "$input"
:IFS=' '
:IFS
代表内部字段分隔符(Internal Field Separator),这里将其设置为一个空格。IFS
用于确定read
命令如何将输入的字符串拆分成多个部分。read -ra parts
:-r
选项告诉read
命令以原始模式读取输入,即不允许反斜杠转义。-a parts
选项告诉read
命令将输入的数据存储到一个数组中,数组的名称是parts
。
<<< "$input"
:这是一个“Here String”,它将input
变量的值作为read
命令的输入源。
这段代码的整体功能是提示用户输入一个表达式,表达式的格式为“数字 运算符 数字”,用户输入后,代码会将用户输入的表达式以空格为分隔符拆分成一个数组,并将数组存储在 parts
变量中。例如,如果用户输入 5 + 3
,那么 parts
数组将包含三个元素,分别是 ["5", "+", "3"]
。这样做方便后续对表达式中的数字和运算符进行单独处理,例如可以根据运算符进行相应的计算操作,通过访问 parts[0]
可以获取第一个数字,parts[1]
可以获取运算符,parts[2]
可以获取第二个数字。
假设以下是一个使用该代码的示例:
read -p "请输入表达式(格式:数字 运算符 数字): " input
IFS=' ' read -ra parts <<< "$input"
echo "第一个数字是: ${parts[0]}"
echo "运算符是: ${parts[1]}"
echo "第二个数字是: ${parts[2]}"
在这个示例中,用户输入表达式后,程序会将输入拆分成数组并存储在 parts
变量中,然后分别输出表达式中的第一个数字、运算符和第二个数字。这为后续进行更复杂的操作,如根据运算符进行相应的计算等提供了便利。
#!/bin/bash
# 检查输入是否为纯数字整数
is_integer() {
# -?
# -69
# 69
if [[ $1 =~ ^-?[0-9]+$ ]]; then
return 0
else
return 1
fi
}
# 主程序
while true; do
read -p "请输入表达式(格式:数字 运算符 数字): " input
# 将输入拆分成数组
IFS=' ' read -ra parts <<< "$input"
# 检查输入参数是否为 3 个
if [ ${#parts[@]} -ne 3 ]; then
echo "输入错误,请使用正确的格式:数字 运算符 数字"
continue
fi
# 3 + 2
num1=${parts[0]}
operator=${parts[1]}
num2=${parts[2]}
# 检查输入是否为纯数字整数
if ! is_integer $num1 ||! is_integer $num2; then
echo "输入错误,数字必须是整数。"
continue
fi
# 检查运算符是否合法
case $operator in
+)
result=$((num1 + num2))
;;
-)
result=$((num1 - num2))
;;
\*)
result=$((num1 * num2))
;;
/)
if [ $num2 -eq 0 ]; then
echo "除数不能为 0。"
continue
else
result=$((num1 / num2))
fi
;;
*)
echo "输入错误,运算符必须是 +、-、* 或 /。"
continue
;;
esac
echo "结果: $result"
done
代码解释:
- 函数
is_integer
:- 该函数使用
=~
运算符和正则表达式^-?[0-9]+$
来检查输入的字符串是否为纯数字整数。 ^
表示字符串的开始,-?
表示可选的负号,[0-9]+
表示一个或多个数字,$
表示字符串的结束。- 如果匹配成功,函数返回 0(
true
),否则返回 1(false
)。
- 该函数使用
- 主程序部分:
- 使用
while true
实现一个无限循环,直到用户输入正确的表达式并计算出结果。 read -p "请输入表达式(格式:数字 运算符 数字): " input
:提示用户输入表达式并读取输入。IFS=' ' read -ra parts <<< "$input"
:使用IFS
(内部字段分隔符)将输入按空格拆分成数组parts
。if [ ${#parts[@]} -ne 3 ]; then...
:检查输入的元素数量是否为 3,如果不是,提示用户输入错误并使用continue
重新开始循环。if! is_integer $num1 ||! is_integer $num2; then...
:调用is_integer
函数检查输入的数字是否为整数,如果不是,提示用户并重新开始循环。case $operator in...
:使用case
语句检查运算符是否合法。+
和-
情况:使用$((num1 + num2))
和$((num1 - num2))
进行简单的加、减运算。*)
情况:对于不合法的运算符,提示用户并重新开始循环。/
情况:进行除法运算,但先检查除数是否为 0,如果为 0,提示用户除数不能为 0 并重新开始循环。
echo "结果: $result"
:输出计算结果。
- 使用
使用方法:
- 将上述代码保存为一个文件,例如
calculator.sh
。 - 给文件添加可执行权限:
chmod +x calculator.sh
。 - 运行脚本:
./calculator.sh
。 - 按照提示输入表达式,例如
5 + 3
,脚本将计算结果并输出。
这个脚本通过函数和 case
语句,结合循环,确保了输入的合法性和程序的健壮性。它可以不断提示用户输入正确的表达式,直到计算出结果,同时对各种可能的错误进行了检查和处理。
请注意,这个脚本还可以进一步优化,例如支持浮点数运算,处理更多的错误情况,以及添加更多的运算符等。
参考答案-2
以下是一个更健壮的交互式 Bash 计算器脚本,采用 case
和函数来提高可读性和可维护性:
#!/bin/bash
# 检查输入是否为纯整数
is_integer() {
[[ $1 =~ ^-?[0-9]+$ ]]
}
# 检查运算符是否有效
is_operator() {
case $1 in
+|-|*|/) return 0 ;;
*) return 1 ;;
esac
}
# 执行计算
calculate() {
local num1=$1
local operator=$2
local num2=$3
case $operator in
+) echo $((num1 + num2)) ;;
-) echo $((num1 - num2)) ;;
*) echo $((num1 * num2)) ;;
/)
if [[ $num2 -eq 0 ]]; then
echo "错误: 除数不能为0"
else
echo $((num1 / num2))
fi
;;
esac
}
# 主逻辑循环
while true; do
echo "请输入计算公式(格式: 数字1 运算符 数字2,例如:3 + 5):"
read -r num1 operator num2
# 检查输入参数数量
if [[ -z $num1 || -z $operator || -z $num2 ]]; then
echo "错误: 请输入完整的三个参数(数字 运算符 数字)。"
continue
fi
# 检查是否为整数
if ! is_integer "$num1" || ! is_integer "$num2"; then
echo "错误: 请输入有效的整数。"
continue
fi
# 检查运算符
if ! is_operator "$operator"; then
echo "错误: 请输入有效的运算符(+ - * /)。"
continue
fi
# 计算并输出结果
result=$(calculate "$num1" "$operator" "$num2")
echo "结果: $num1 $operator $num2 = $result"
done
脚本说明:
函数封装:
is_integer
: 检查是否为纯整数。is_operator
: 检查运算符是否为+ - * /
。calculate
: 根据输入执行对应运算。
交互式输入:
- 使用
read
接收用户输入,并分离为三个变量。
- 使用
输入验证:
- 确保输入有三个参数。
- 验证数字是否合法。
- 验证运算符是否合法。
循环重试:
- 使用
while true
实现循环,当输入错误时不会退出,提示用户重新输入。
- 使用
友好提示:
- 针对不同错误场景提供详细提示。
运行此脚本时,它会持续运行,直到用户手动退出(如 Ctrl+C
)。
6.开发非交互的服务启动脚本
# 需求,使用case开发非交互的服务管理脚本,添加颜色状态功能
# 具体开发思路,可以参考systemctl是如何帮你管理程序的即可。
# 这里的脚本,等于是管理nginx的脚本,一个服务单独一个脚本即可。
代码
#!/bin/bash
source /etc/init.d/functions
your_service=$1
case $your_service in
start)
echo "${your_service} 启动中"
sleep 1
nginx
if [ $? -eq 0 ];then
action "${your_service} 启动成功" /bin/true
else
action "${your_service} 启动失败" /bin/false
fi
;;
stop)
echo "${your_service} 停止中"
sleep 1
nginx -s stop
if [ $? -eq 0 ];then
action "${your_service} 以停止" /bin/true
else
action "${your_service} 停止报错!!" /bin/false
fi
;;
restart)
echo "${your_service} 重启中"
nginx -s stop
sleep 1
nginx
if [ $? -eq 0 ];then
action "nginx 重启成功" /bin/true
else
action "nginx 重启失败" /bin/false
fi
;;
reload)
nginx -s reload
if [ $? -eq 0 ];then
action "nginx正在重新加载" /bin/true
else
action "nginx 重新载入失败" /bin/false
fi
;;
check)
echo "检测 ${your_service} 语法中"
nginx -t
;;
status)
echo "检查 ${your_service} 运行状态中"
if [ ! -f "/run/nginx.pid" ];then
echo "nginx未运行!!"
else
echo "nginx运行中!进程id是$(cat /run/nginx.pid)"
fi
;;
*)
echo "用法错误,正确用法是:{start|stop|restart|reload|check}"
esac
参考答案1
以下是一个使用 case
开发的非交互式的 Nginx 服务管理脚本,并添加了颜色状态功能:
开发思路:
- 使用
case
语句处理不同的操作,如start
、stop
、restart
、status
等。 - 对于
start
、stop
和restart
操作,使用systemctl
命令执行相应操作,并检查命令的执行结果,使用$?
获取退出状态码,判断操作是否成功。 - 对于
status
操作,使用systemctl status nginx
获取服务状态,并根据状态输出不同颜色的信息,使用echo -e
命令输出彩色文本。 - 对于不支持的操作,给出相应的错误提示。
#!/bin/bash
# 定义颜色变量
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
NC='\033[0m' # No Color
case $1 in
start)
echo "正在启动 Nginx 服务..."
systemctl start nginx
if [ $? -eq 0 ]; then
echo -e "${GREEN}Nginx 服务已成功启动。${NC}"
else
echo -e "${RED}启动 Nginx 服务失败。${NC}"
fi
;;
stop)
echo "正在停止 Nginx 服务..."
systemctl stop nginx
if [ $? -eq 0 ]; then
echo -e "${GREEN}Nginx 服务已成功停止。${NC}"
else
echo -e "${RED}停止 Nginx 服务失败。${NC}"
fi
;;
restart)
echo "正在重启 Nginx 服务..."
systemctl restart nginx
if [ $? -eq 0 ]; then
echo -e "${GREEN}Nginx 服务已成功重启。${NC}"
else
echo -e "${RED}重启 Nginx 服务失败。${NC}"
fi
;;
status)
echo "正在检查 Nginx 服务状态..."
systemctl status nginx > /dev/null 2>&1
if [ $? -eq 0 ]; then
echo -e "${GREEN}Nginx 服务正在运行。${NC}"
else
echo -e "${YELLOW}Nginx 服务未运行。${NC}"
fi
;;
*)
echo "不支持的操作。请使用 start、stop、restart 或 status。"
;;
esac
代码解释:
- 颜色变量:
RED='\033[0;31m'
:定义红色的 ANSI 转义码。GREEN='\033[0;32m'
:定义绿色的 ANSI 转义码。YELLOW='\033[0;33m'
:定义黄色的 ANSI 转义码。NC='\033[0m'
:定义无颜色的 ANSI 转义码,用于恢复正常颜色。
- case 语句部分:
start
:使用systemctl start nginx
启动 Nginx 服务,并通过if [ $? -eq 0 ];
检查systemctl
命令的退出状态码。如果为 0,表示成功,输出绿色的成功消息,否则输出红色的失败消息。stop
:与start
类似,但执行systemctl stop nginx
来停止服务。restart
:使用systemctl restart nginx
重启服务,并检查退出状态码。status
:使用systemctl status nginx
检查服务状态,将输出重定向到/dev/null 2>&1
以避免输出多余信息,根据状态码输出不同颜色的状态信息。*)
:对于不支持的操作,输出错误提示。
使用方法:
- 将上述脚本保存为一个文件,例如
nginx_service.sh
。 - 给文件添加可执行权限:
chmod +x nginx_service.sh
。 - 执行不同的操作:
- 启动服务:
./nginx_service.sh start
- 停止服务:
./nginx_service.sh stop
- 重启服务:
./nginx_service.sh restart
- 查看服务状态:
./nginx_service.sh status
- 启动服务:
这个脚本使用 case
语句清晰地处理了不同的服务管理操作,同时使用颜色状态信息方便用户查看服务的状态和操作结果。根据实际需求,你可以扩展该脚本以支持更多的服务管理功能,如查看日志、修改配置等。
此外,需要注意的是,脚本中使用了 systemctl
命令,因此需要在使用 systemd
的系统上运行,并且需要有足够的权限执行相应的服务管理操作。
参考答案-2
以下是一个基于 case
的非交互式 Nginx 服务管理脚本,包含颜色状态功能,用于模仿 systemctl
的基本功能:
脚本代码
#!/bin/bash
# 颜色定义
GREEN="\033[32m"
RED="\033[31m"
YELLOW="\033[33m"
BLUE="\033[34m"
RESET="\033[0m"
# Nginx 服务控制命令(根据实际安装路径调整)
NGINX_CMD="/usr/sbin/nginx"
NGINX_PID_FILE="/var/run/nginx.pid"
# 打印带颜色的状态信息
print_status() {
local status=$1
local message=$2
case $status in
success) echo -e "${GREEN}[成功]${RESET} $message" ;;
error) echo -e "${RED}[错误]${RESET} $message" ;;
warning) echo -e "${YELLOW}[警告]${RESET} $message" ;;
info) echo -e "${BLUE}[信息]${RESET} $message" ;;
esac
}
# 检查 Nginx 是否运行
is_running() {
if [[ -f $NGINX_PID_FILE && -s $NGINX_PID_FILE ]]; then
if ps -p "$(cat "$NGINX_PID_FILE")" &>/dev/null; then
return 0
fi
fi
return 1
}
# 启动 Nginx
start_nginx() {
if is_running; then
print_status warning "Nginx 已经在运行 (PID: $(cat "$NGINX_PID_FILE"))。"
else
$NGINX_CMD &>/dev/null
if is_running; then
print_status success "Nginx 启动成功 (PID: $(cat "$NGINX_PID_FILE"))。"
else
print_status error "Nginx 启动失败,请检查配置或日志。"
fi
fi
}
# 停止 Nginx
stop_nginx() {
if is_running; then
kill "$(cat "$NGINX_PID_FILE")" &>/dev/null
sleep 1
if is_running; then
print_status error "Nginx 停止失败,请手动检查进程。"
else
print_status success "Nginx 已停止。"
fi
else
print_status warning "Nginx 未运行,无需停止。"
fi
}
# 重启 Nginx
restart_nginx() {
stop_nginx
start_nginx
}
# 检查 Nginx 状态
status_nginx() {
if is_running; then
print_status success "Nginx 正在运行 (PID: $(cat "$NGINX_PID_FILE"))。"
else
print_status error "Nginx 未运行。"
fi
}
# 显示用法
usage() {
echo "用法: $0 {start|stop|restart|status}"
exit 2
}
# 主程序入口
case $1 in
start) start_nginx ;;
stop) stop_nginx ;;
restart) restart_nginx ;;
status) status_nginx ;;
*) usage ;;
esac
脚本说明
颜色功能:
- 使用 ANSI 转义序列定义了四种颜色:绿色(成功)、红色(错误)、黄色(警告)、蓝色(信息)。
功能实现:
start_nginx
: 启动 Nginx 服务,检查是否已运行。stop_nginx
: 停止 Nginx 服务,检查是否成功。restart_nginx
: 依次调用停止和启动函数。status_nginx
: 检查 Nginx 的运行状态。
状态检测:
- 根据
nginx.pid
文件和ps
检测服务运行状态。
- 根据
用法提示:
- 脚本未提供有效参数时,显示用法信息。
命令调整:
- 如果
nginx
的实际路径或运行方式不同,可以通过修改$NGINX_CMD
和$NGINX_PID_FILE
变量适配。
- 如果
兼容性:
- 适用于大多数支持 Bash 的 Linux 发行版。
使用示例
./nginx_service.sh start # 启动 Nginx
./nginx_service.sh stop # 停止 Nginx
./nginx_service.sh restart # 重启 Nginx
./nginx_service.sh status # 检查 Nginx 状态
7.日志分析多功能脚本
123.123.132.90 - - [18/Dec/2024:20:40:06 +0800] "GET / HTTP/1.1" 200 2103 "-" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Mobile Safari/537.36 EdgA/131.0.0.0"
123.123.132.90 - - [18/Dec/2024:20:40:06 +0800] "GET /static/css/chunk-libs.3dfb7769.css HTTP/1.1" 200 3568 "http://yuchaoit.cn/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Mobile Safari/537.36 EdgA/131.0.0.0"
123.123.132.90 - - [18/Dec/2024:20:40:06 +0800] "GET /static/css/app.7963745b.css HTTP/1.1" 200 263442 "http://yuchaoit.cn/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Mobile Safari/537.36 EdgA/131.0.0.0"
123.123.132.90 - - [18/Dec/2024:20:40:06 +0800] "GET /static/js/chunk-libs.a519c9f8.js HTTP/1.1" 200 278469 "http://yuchaoit.cn/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Mobile Safari/537.36 EdgA/131.0.0.0"
123.123.132.90 - - [18/Dec/2024:20:40:08 +0800] "GET /static/js/app.11993d37.js HTTP/1.1" 200 199026 "http://yuchaoit.cn/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Mobile Safari/537.36 EdgA/131.0.0.0"
123.123.132.90 - - [18/Dec/2024:20:40:17 +0800] "GET /static/js/chunk-elementUI.c1fcb5b4.js HTTP/1.1" 200 774050 "http://yuchaoit.cn/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Mobile Safari/537.36 EdgA/131.0.0.0"
123.123.132.90 - - [18/Dec/2024:20:40:18 +0800] "GET /static/js/chunk-25805cc4.ce91a669.js HTTP/1.1" 200 95585 "http://yuchaoit.cn/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Mobile Safari/537.36 EdgA/131.0.0.0"
123.123.132.90 - - [18/Dec/2024:20:40:18 +0800] "GET /static/css/chunk-5df68752.3fb1aada.css HTTP/1.1" 200 679 "http://yuchaoit.cn/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Mobile Safari/537.36 EdgA/131.0.0.0"
123.123.132.90 - - [18/Dec/2024:20:40:18 +0800] "GET /static/js/chunk-5df68752.b997e269.js HTTP/1.1" 200 5652 "http://yuchaoit.cn/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Mobile Safari/537.36 EdgA/131.0.0.0"
45.140.17.52 - - [18/Dec/2024:20:40:26 +0800] "\x03\x00\x00/*\xE0\x00\x00\x00\x00\x00Cookie: mstshash=Administr" 400 150 "-" "-"
需求
# 按要求分析nginx的日志
# 打印功能选择菜单
1. 显示当前机器信息
2. 查询pv,uv ,page view,访问者 记录,
# pv 刷新一次记录一次
# uv,根据你
3. 显示访问量最高的ip,以及访问次数
4. 显示访问最频繁的业务url,最频繁的页面
5. 显示各种搜索引擎爬虫访问本站的次数
6. 显示都有哪些客户端访问了本网站
提示
nginx作为优秀的网站服务器,通过日志提取用户访问行为是最合适的了
pv,page view,表示页面浏览量,点击量,用户刷新一次,就是一个pv,也就是一个请求,一次页面浏览,因此只作为网站的一个总览访问总体访问量(基于请求方法字段提取pv)
uv ,表示unique visitor,指的是同一个客户端发出的请求,只被计算一次,基于去重后的客户端ip作为独立访客。(基于remote_addr提取 uv)
脚本
#!/bin/bash
nginx_file=$1
echo -e "------------
------日志分析系统,功能菜单------
1. 显示当前机器信息
2. 查询pv,uv
3. 显示访问量最高的10个ip,以及访问次数
4. 显示访问最频繁的10个业务url,最频繁的页面
5. 显示各种搜索引擎爬虫访问本站的次数
6. 显示都有哪些客户端访问了本网站
-------------"
read -p "请输入您的选择:" num
case $num in
1)
echo -e "===========当前机器信息=======
服务器名:$(hostname)
服务器IP: $(hostname -I
# 服务eth0地址: $(xxx)
#
当前系统时间:$(date +%T_%F)
当前登录用户:$USER
=========="
;;
2)
echo -e "=========当前机器pv、uv统计数据======
pv页面访问总量:$(wc -l $nginx_file)
========================================================================
uv独立访客数量:$(awk '{print $1}' $nginx_file |sort |uniq -c |wc -l)
"
;;
3)
echo -e "=========访问量最高的10个IP,访问次数==============
$(awk '{print $1}' $nginx_file |sort |uniq -c |sort -n -r |head )"
;;
4)
echo -e "=======访问量最高的10个业务url,最频繁的页面=====
$(awk '{print $7}' $nginx_file | sort | uniq -c |sort -rn |head -10)"
;;
5)
echo -e "======显示各种搜索引擎爬虫访问本站的次数========
百度爬虫访问次数:$(grep -Ei 'baiduspider' $nginx_file |wc -l)
必应爬虫访问次数:$(grep -Ei 'bingbot' $nginx_file |wc -l)
谷歌爬虫访问次数:$(grep -Ei 'googlebot' $nginx_file |wc -l)
搜狗爬虫访问次数:$(grep -Ei 'sogou web spider*' $nginx_file |wc -l)
易搜爬虫访问次数:$( grep -Ei 'yisou' $nginx_file |wc -l)
"
;;
6)
echo -e "========访问本网站的客户端种前10种是:==============
$( awk '{print $12}' $nginx_file|sort |uniq -c |sort -rn |head -10)"
;;
*)
echo "请按要求输入选项!!!谢谢!"
;;
esac
参考答案-1
以下是一个可以分析 Nginx 日志并提供指定功能的 Bash 脚本:
脚本代码
#!/bin/bash
# Nginx 日志文件路径
LOG_FILE="/var/log/nginx/access.log"
# 检查日志文件是否存在
if [[ ! -f $LOG_FILE ]]; then
echo "日志文件不存在,请检查路径: $LOG_FILE"
exit 1
fi
# 显示当前机器信息
show_system_info() {
echo "===== 当前机器信息 ====="
echo "主机名: $(hostname)"
echo "操作系统: $(uname -a)"
echo "IP 地址: $(hostname -I | awk '{print $1}')"
echo "当前时间: $(date)"
echo "========================"
}
# 查询 PV 和 UV
query_pv_uv() {
echo "===== 查询 PV 和 UV ====="
PV=$(wc -l < "$LOG_FILE")
UV=$(awk '{print $1}' "$LOG_FILE" | sort | uniq | wc -l)
echo "总 PV(页面访问量): $PV"
echo "总 UV(独立访客数): $UV"
echo "========================"
}
# 显示访问量最高的 IP 和访问次数
top_ip() {
echo "===== 访问量最高的 IP ====="
awk '{print $1}' "$LOG_FILE" | sort | uniq -c | sort -rn | head -1 | awk '{print "IP:", $2, "访问次数:", $1}'
echo "==========================="
}
# 显示访问最频繁的业务 URL 和页面
top_url() {
echo "===== 访问最频繁的 URL ====="
awk '{print $7}' "$LOG_FILE" | sort | uniq -c | sort -rn | head -1 | awk '{print "URL:", $2, "访问次数:", $1}'
echo "============================"
}
# 显示搜索引擎爬虫访问次数
crawler_count() {
echo "===== 搜索引擎爬虫访问统计 ====="
grep -E "Googlebot|Bingbot|Baiduspider|YandexBot|Sogou" "$LOG_FILE" | awk '{print $12}' | sort | uniq -c | sort -rn
echo "================================"
}
# 显示所有客户端
show_clients() {
echo "===== 客户端信息 ====="
awk -F\" '{print $6}' "$LOG_FILE" | sort | uniq -c | sort -rn | head -10
echo "======================"
}
# 打印菜单
show_menu() {
echo "===== Nginx 日志分析菜单 ====="
echo "1. 显示当前机器信息"
echo "2. 查询 PV 和 UV"
echo "3. 显示访问量最高的 IP 和访问次数"
echo "4. 显示访问最频繁的 URL 和页面"
echo "5. 显示搜索引擎爬虫访问本站的次数"
echo "6. 显示都有哪些客户端访问了本网站"
echo "0. 退出"
echo "============================="
echo -n "请选择功能: "
}
# 主程序入口
while true; do
show_menu
read -r choice
case $choice in
1) show_system_info ;;
2) query_pv_uv ;;
3) top_ip ;;
4) top_url ;;
5) crawler_count ;;
6) show_clients ;;
0) echo "退出程序"; exit 0 ;;
*) echo "无效选项,请重新选择。" ;;
esac
done
脚本说明
日志路径:
- 默认路径为
/var/log/nginx/access.log
,可以根据需要修改变量LOG_FILE
。
- 默认路径为
功能说明:
- 功能 1: 使用系统命令显示当前主机信息。
- 功能 2: 利用
wc
和awk
分别统计 PV(总行数)和 UV(独立 IP)。 - 功能 3: 使用
awk
和sort
找出访问次数最多的 IP。 - 功能 4: 找出访问最频繁的 URL。
- 功能 5: 使用正则匹配统计常见搜索引擎爬虫的访问次数。
- 功能 6: 显示所有客户端信息,包括浏览器和操作系统。
交互式菜单:
- 用户通过输入数字选择功能,选项无效时会提示重新输入。
兼容性:
- 脚本基于标准 Linux 工具开发,适用于大多数发行版。
性能优化:
- 使用
sort
和uniq -c
提升统计性能。
- 使用
使用方式
- 将脚本保存为
nginx_log_analysis.sh
。 - 确保脚本可执行:
chmod +x nginx_log_analysis.sh
- 执行脚本:
./nginx_log_analysis.sh
参考答案-2
以下是一个实现上述功能的 Bash 脚本的开发思路及代码示例:
开发思路:
- 打印功能选择菜单:使用
echo
命令打印出用户可以选择的功能菜单。 - 根据用户选择执行相应操作:使用
read
命令读取用户的选择,然后使用case
语句根据不同的选择执行不同的功能。 - 显示当前机器信息:使用
uname
命令获取操作系统信息,hostname
命令获取主机名,uptime
命令获取系统运行时间,free -m
命令获取内存信息等。 - 查询 PV 和 UV:需要解析 Nginx 的访问日志文件,统计不同 IP 的数量(UV)和日志行数(PV)。
- 显示访问量最高的 IP 及访问次数:使用
awk
或sort
和uniq
等工具统计 Nginx 日志文件中每个 IP 出现的次数,并找出最高的。 - 显示访问最频繁的业务 URL 和页面:通过解析 Nginx 日志文件,找出访问最频繁的 URL。
- 显示搜索引擎爬虫访问次数:通过解析 Nginx 日志文件,识别出搜索引擎爬虫的用户代理(User-Agent),并统计其访问次数。
- 显示访问网站的客户端:通过解析 Nginx 日志文件,找出不同的客户端信息。
#!/bin/bash
# 假设 Nginx 日志文件的路径,根据实际情况修改
LOG_FILE="/var/log/nginx/access.log"
# 打印功能选择菜单
print_menu() {
echo "请选择功能:"
echo "1. 显示当前机器信息"
echo "2. 查询 PV, UV"
echo "3. 显示访问量最高的 IP,以及访问次数"
echo "4. 显示访问最频繁的业务 URL,最频繁的页面"
echo "5. 显示各种搜索引擎爬虫访问本站的次数"
echo "6. 显示都有哪些客户端访问了本网站"
echo "q. 退出"
}
# 显示当前机器信息
show_machine_info() {
echo "操作系统:$(uname -a)"
echo "主机名:$(hostname)"
echo "系统运行时间:$(uptime)"
echo "内存使用情况:"
free -m
}
# 查询 PV 和 UV
show_pv_uv() {
# PV 是日志文件的行数
pv=$(wc -l < $LOG_FILE)
# UV 是不同 IP 的数量
uv=$(awk '{print $1}' $LOG_FILE | sort | uniq | wc -l)
echo "PV: $pv"
echo "UV: $uv"
}
# 显示访问量最高的 IP 及访问次数
show_top_ip() {
# 使用 awk 统计每个 IP 的访问次数,并找出最高的
top_ip=$(awk '{print $1}' $LOG_FILE | sort | uniq -c | sort -nr | head -n 1)
echo "访问量最高的 IP 及访问次数:"
echo "$top_ip"
}
# 显示访问最频繁的业务 URL 和页面
show_top_url() {
# 使用 awk 统计每个 URL 的访问次数,并找出最高的
top_url=$(awk '{print $7}' $LOG_FILE | sort | uniq -c | sort -nr | head -n 1)
echo "访问最频繁的业务 URL 及访问次数:"
echo "$top_url"
}
# 显示搜索引擎爬虫访问次数
show_crawler_count() {
# 识别常见搜索引擎爬虫的 User-Agent,并统计其访问次数
crawler_count=$(awk 'tolower($(NF-1)) ~ /googlebot|bingbot|yandexbot|baiduspider|sogou|360spider|yahoo! slurp/ {print $(NF-1)}' $LOG_FILE | sort | uniq -c)
echo "搜索引擎爬虫访问次数:"
echo "$crawler_count"
}
# 显示访问网站的客户端
show_clients() {
# 找出不同的客户端信息
clients=$(awk '{print $(NF-1)}' $LOG_FILE | sort | uniq)
echo "访问网站的客户端:"
echo "$clients"
}
while true; do
print_menu
read -p "请输入选项: " choice
case $choice in
1)
show_machine_info
;;
2)
show_pv_uv
;;
3)
show_top_ip
;;
4)
show_top_url
;;
5)
show_crawler_count
;;
6)
show_clients
;;
q)
echo "退出程序。"
exit 0
;;
*)
echo "无效的选项,请重新输入。"
;;
esac
done
代码解释:
- 变量定义:
LOG_FILE
:定义了 Nginx 日志文件的路径,可根据实际情况修改。
- 函数定义:
print_menu
:打印用户可以选择的功能菜单。show_machine_info
:使用uname
、hostname
、uptime
和free
等命令显示当前机器信息。show_pv_uv
:使用wc -l
统计日志文件的行数(PV),使用awk
和sort
、uniq
等工具统计不同 IP 的数量(UV)。show_top_ip
:使用awk
提取 IP 地址,通过sort
、uniq -c
和sort -nr
找出访问量最高的 IP 及其访问次数。show_top_url
:使用awk
提取 URL,通过sort
、uniq -c
和sort -nr
找出访问最频繁的 URL 及其访问次数。show_crawler_count
:使用awk
提取用户代理(User-Agent),筛选出常见搜索引擎爬虫的 User-Agent,并统计其访问次数。show_clients
:使用awk
提取用户代理(User-Agent),并找出不同的客户端信息。
- 主程序部分:
while true
:创建一个无限循环,不断打印菜单和读取用户输入。read -p "请输入选项: " choice
:读取用户的选择。case $choice in...
:根据用户的选择执行相应的功能,使用case
语句处理不同的操作,对于无效的选择,提示用户重新输入,对于q
选项,退出程序。
使用方法:
- 将上述脚本保存为一个文件,例如
nginx_log_analysis.sh
。 - 给文件添加可执行权限:
chmod +x nginx_log_analysis.sh
。 - 运行脚本:
./nginx_log_analysis.sh
。 - 根据菜单提示选择相应的功能。
请注意,上述脚本假设 Nginx 日志文件的格式为标准的 Nginx 访问日志格式,不同的日志格式可能需要调整 awk
命令的字段位置。此外,脚本中使用了一些基本的文本处理工具(如 awk
、sort
、uniq
等),对于复杂的日志分析需求,可能需要更复杂的正则表达式和文本处理逻辑。你可以根据实际的日志文件和需求进一步优化和扩展脚本。
8.阅读同事写脚本
在工作里,阅读公司现有的脚本是常事,学会添加注释,理解脚本作用,然后可以开始维护脚本,维护项目。
上班之后,一般的工作技巧是
- 阅读ansible配置文件,主机清单文件,roles或者playbook,整体了解公司运维部署架构
- 然后再一层层的细看,从ansible的剧本,拆解,每一个组件的细节,涉及的配置文件,shell脚本
- 然后再从细节,去理解配置文件的功能,shell的细节。
- 自己写好总结文档,学习笔记,可以随时拿出来看。
这里是于超老师从jumpserver最新版的github代码库下载一个sh脚本,如果现在你就是这家飞致云新入职员工,你就得去阅读,维护该堡垒机的所有发布脚本。
来,试着给如下脚本,加上注释,目标如下
1.学习生产环境下其他工程师写的脚本写法
2.阅读,加注释,理解他人的脚本。
#!/bin/bash
if grep -q 'source /opt/autoenv/activate.sh' ~/.bashrc; then
echo -e "\033[31m 正在自动载入 python 环境 \033[0m"
else
echo -e "\033[31m 不支持自动升级,请参考 http://docs.jumpserver.org/zh/docs/upgrade.html 手动升级 \033[0m"
exit 0
fi
source ~/.bashrc
cd `dirname $0`/ && cd .. && ./jms stop
jumpserver_backup=/tmp/jumpserver_backup$(date -d "today" +"%Y%m%d_%H%M%S")
mkdir -p $jumpserver_backup
cp -r ./* $jumpserver_backup
echo -e "\033[31m 是否需要备份Jumpserver数据库 \033[0m"
stty erase ^H
read -p "确认备份请按Y,否则按其他键跳过备份 " a
if [ "$a" == y -o "$a" == Y ];then
echo -e "\033[31m 正在备份数据库 \033[0m"
echo -e "\033[31m 请手动输入数据库信息 \033[0m"
read -p '请输入Jumpserver数据库ip:' DB_HOST
read -p '请输入Jumpserver数据库端口:' DB_PORT
read -p '请输入Jumpserver数据库名称:' DB_NAME
read -p '请输入有权限导出数据库的用户:' DB_USER
read -p '请输入该用户的密码:' DB_PASSWORD
mysqldump -h$DB_HOST -P$DB_PORT -u$DB_USER -p$DB_PASSWORD $DB_NAME > /$jumpserver_backup/$DB_NAME$(date -d "today" +"%Y%m%d_%H%M%S").sql || {
echo -e "\033[31m 备份数据库失败,请检查输入是否有误 \033[0m"
exit 1
}
echo -e "\033[31m 备份数据库完成 \033[0m"
else
echo -e "\033[31m 已取消备份数据库操作 \033[0m"
fi
git pull && pip install -r requirements/requirements.txt && cd utils && sh make_migrations.sh
cd .. && ./jms start all -d
echo -e "\033[31m 请检查jumpserver是否启动成功 \033[0m"
echo -e "\033[31m 备份文件存放于$jumpserver_backup目录 \033[0m"
stty erase ^?
exit 0