以前写了系列的shell实战的文章,获得了挺多小伙伴的关注,遇到有些对shell不太熟悉小伙伴,因此有个想法写一篇shell入门的文章。
时间流逝,再回头去看看过去的东西,才会发现哪些东西比较重要,故撰此文,记录我在过去学习和使用shell语言过程当中我我的以为比较重要的部分,作一个小总结和分享。git
文章中使用到的代码位置: gitee.com/dhar/YTTInj…
和
gitee.com/dhar/ShellL…github
文章内容结构以下:正则表达式
语法shell
文件数组
sed流编辑ruby
模块bash
输入和菜单less
定义一个变量和其余语言的相似,shell是弱类型语言因此不须要使用类型限定,而且变量能够修改类型,下面的例子定义了一个字符串类型的str
变量,以后修改成数值类型curl
注意点:变量等号两边不能有空格出现函数
str="string"
echo $str
echo ${str}
str=123
echo $str
复制代码
变量能够赋值给另外一个变量和打印,当变量被使用的时候须要在变量名称前面加上$
符号,还有另外一种方式是把变量名放在${}
括号中使用,能够把命令执行结果做为右值赋值给变量
str2=$str
echo $str2;
str3=${str}
echo ${str3}
curDir=$(pwd)
echo "curDir = ${curDir}"
curDirCon=`ls`
echo "curDirCon = ${curDir2}"
# 输出:
=======变量=======
string
string
123
123
123
curDir = /Users/aron/git-repo/ShellLearning/helloshell
curDirCon = data
syntax.sh
复制代码
由于shell没有单步调试和其余功能强大的IDE,因此打印功能就常用到,此外打印功能还能够当作函数的返回值,比return做为函数的返回值功能更强大,shell 使用echo
打印,内容默认输出到控制台中,echo
能够打印字符串、变量、以及字符串中嵌入变量的混个内容,echo
有几重要的参数选项
\t
显示为制表符而不是显示输出\t
str4="string4"
echo $str4
echo "str4=$str4"
echo "str4=${str4}str3=${str3}"
# 输出:
=======打印=======
string4
str4=string4
str4=string4str3=123
复制代码
expr
执行算术运算注意点:*
乘法运算符号须要转义
echo "=======运算======="
result=$(expr 5 + 5)
echo ${result}
result=$(expr 16 - 5)
echo ${result}
result=$(expr 5 \* 5)
echo ${result}
result=$(expr 28 / 5)
echo ${result}
# 输出:
=======expr运算=======
10
11
25
5
复制代码
[]
执行算术[]
执行算术比expr
简单多了,而且*
乘法运算符号不须要转义
echo "=======[]运算======="
result=$[5 + 5]
echo ${result}
result=$[16 - 5]
echo ${result}
result=$[5 * 5]
echo ${result}
result=$[28 / 5]
echo ${result}
# 输出:
=======[]运算=======
10
11
25
5
复制代码
控制使用if
/else
/fi
语法,典型的数值比较以下
if [[ 3 > 7 ]]; then
echo "hehe"
else
echo "yes"
fi
# 输出:
yes
复制代码
还可使用下面的比较符号
比较符 | 描述 |
---|---|
n1 -eq n2 | 检查n1是否与n2相等 |
n1 -ge n2 | 检查n1是否大于或等于n2 |
n1 -gt n2 | 检查n1是否大于n2 |
n1 -le n2 | 检查n1是否小于或等于n2 |
n1 -lt n2 | 检查n1是否小于n2 |
n1 -ne n2 | 检查n1是否不等于n2 |
一个简单的9*9乘法口诀表的例子
echo "9*9======="
i=1
j=1
line=""
while [[ i -lt 10 ]]; do
j=1
line=""
until [[ j -eq 10 ]]; do
if [[ j -le i ]]; then
result=$(expr $i \* $j)
resultStr="$j X $i = $result"
line=${line}${resultStr}"\t"
fi
j=$(expr $j + 1)
done
echo -e ${line}
i=$(expr $i + 1)
done
# 输出:
9*9=======
1 X 1 = 1
1 X 2 = 2 2 X 2 = 4
1 X 3 = 3 2 X 3 = 6 3 X 3 = 9
1 X 4 = 4 2 X 4 = 8 3 X 4 = 12 4 X 4 = 16
1 X 5 = 5 2 X 5 = 10 3 X 5 = 15 4 X 5 = 20 5 X 5 = 25
1 X 6 = 6 2 X 6 = 12 3 X 6 = 18 4 X 6 = 24 5 X 6 = 30 6 X 6 = 36
1 X 7 = 7 2 X 7 = 14 3 X 7 = 21 4 X 7 = 28 5 X 7 = 35 6 X 7 = 42 7 X 7 = 49
1 X 8 = 8 2 X 8 = 16 3 X 8 = 24 4 X 8 = 32 5 X 8 = 40 6 X 8 = 48 7 X 8 = 56 8 X 8 = 64
1 X 9 = 9 2 X 9 = 18 3 X 9 = 27 4 X 9 = 36 5 X 9 = 45 6 X 9 = 54 7 X 9 = 63 8 X 9 = 72 9 X 9 = 81
======= =======
复制代码
比较符 | 描述 |
---|---|
str1 = str2 | 检查str1是否和str2相同 |
str1 != str2 | 检查str1是否和str2不一样 |
str1 < str2 | 检查str1是否比str2小 |
str1 > str2 | 检查str1是否比str2大 |
-n str1 | 检查str1的长度是否非0 |
-z str1 | 检查str1的长度是否为0 |
echo "=======控制字符串比较======="
str1="abc"
str2="abd"
if [[ $str1 > $str2 ]]; then
echo "$str1 大于 $str2"
else
echo "$str1 小于等于 $str2"
fi
if [[ -z $str1 ]]; then
echo "str1 为空"
else
echo "str1 不为空"
fi
str1=""
if [[ -z $str1 ]]; then
echo "str1 为空"
else
echo "str1 不为空"
fi
# 输出:
=======控制字符串比较=======
abc 小于等于 abd
str1 不为空
str1 为空
复制代码
比较符 | 描述 |
---|---|
-d file | 检查file是否存在并是一个目录 |
-e file | 检查file是否存在 |
-f file | 检查file是否存在并是一个文件 |
-r file | 检查file是否存在并可读 |
-s file | 检查file是否存在并不是空 |
-w file | 检查file是否存在并可写 |
-x file | 检查file是否存在并可执行 |
-O file | 检查file是否存在并属当前用户全部 |
-G file | 检查file是否存在而且默认组与当前用户相同 |
file1 -nt file2 | 检查file1是否比file2新 |
file1 -ot file2 | 检查file1是否比file2旧 |
echo "=======控制文件比较======="
file="syntax.sh"
if [[ -e $file ]]; then
echo "${file} 文件存在"
else
echo "${file} 文件不存在"
fi
if [[ -f $file ]]; then
echo "${file} 是一个文件"
else
echo "${file} 不是一个文件"
fi
if [[ -d $file ]]; then
echo "${file} 是一个文件夹"
else
echo "${file} 不是一个文件夹"
fi
# 输出:
=======控制文件比较=======
syntax.sh 文件存在
syntax.sh 是一个文件
syntax.sh 不是一个文件夹
复制代码
echo "=======循环for======="
num=0
for (( i = 0; i < 10; i++ )); do
num=$[$num + $i]
done
echo "result = ${num}"
# 输出:
=======循环for=======
result = 45
复制代码
data
文件内容以下:
➜ helloshell git:(master) ✗ cat data
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.%
复制代码
echo "=======循环for in======="
file="data"
IFS_OLD=$IFS
IFS=$'\n'
for line in $(cat $file)
do
echo "${line}"
done
IFS=${IFS_OLD}
# 输出:
=======循环for in=======
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
复制代码
while
表示条件知足执行循环,好比下面的例子是9*9乘法口诀表中的一部分,表示i从1循环到9
i=1
while [[ i -lt 10 ]]; do
i=$(expr $i + 1)
done
复制代码
until
和while
相反,表示条件不知足执行循环,好比下面的例子是9*9乘法口诀表中的一部分,表示j从1循环到9
j=1
line=""
until [[ j -eq 10 ]]; do
if [[ j -le i ]]; then
result=$(expr $i \* $j)
resultStr="$j X $i = $result"
line=${line}${resultStr}"\t"
fi
j=$(expr $j + 1)
done
echo -e ${line}
复制代码
数组的定义以下 declare -a array_name
注意:osx系统由于bash
的版本过低,只能定义索引数组,在bash
版本高于4.1的版本可使用declare -A array_name
定义关联数组
如下的代码片定义一个数组,用于保存配置文件中的内容,而后使用for循环遍历数组内容输出到控制台。
####### 数据定义
# 定义保存类名称的数组
declare -a config_content_array
cfg_line_count=0
# 一、读取配置文件内容保存到数组中
read_config_content_to_array() {
# 读取配置文件
echo "开始读取配置文件..."
# mark: p291
IFS_OLD=$IFS
IFS=$'\n'
# 删除文件行首的空白字符 http://www.jb51.net/article/57972.htm
for line in $(cat $cfg_file | sed 's/^[ \t]*//g')
do
is_comment=$(expr "$line" : '^#.*')
echo "line=${line} is_common=${is_comment}"
if [[ ${#line} -eq 0 ]] || [[ $(expr "$line" : '^#.*') -gt 0 ]]; then
echo "blank line or comment line"
else
config_content_array[$cfg_line_count]=$line
cfg_line_count=$[ $cfg_line_count + 1 ]
echo "line>>>>${line}"
fi
done
IFS=${IFS_OLD}
for (( i = 0; i < ${#config_content_array[@]}; i++ )); do
config_content=${config_content_array[i]};
echo "config_content>>>>>>${config_content}"
done
}
复制代码
方法的定义有两种方式
方法返回值的处理有三种方式
方法的参数
echo "=======方法======="
function func1 {
echo "func1 invoked"
# 最大的返回值为256,超过了256取模的结果,280%256=24,最终返回24
return 280;
}
func2() {
echo "return value"
}
# 检测文件夹存在的方法,结果保存在全局变量`CheckInputDestDirRecursiveReturnValue`中
# 参数一:检测的文件夹路径
# 参数二:提示消息字符串
# 使用方式以下,去掉注释
# # 导入工具脚本
# . ./FileUtil.sh
# # 检测class_search_dir
# checkDirCore $class_search_dir "指定类的查找目录不存在"
# class_search_dir=${CheckInputDestDirRecursiveReturnValue}
checkDirCore() {
to_process_dir=$1
message=$2
echo "scriptName=${0} paramsCount=${#}"
# 需处理源码目录检查
if [[ -d $to_process_dir ]]; then
echo "目录存在 $to_process_dir"
CheckInputDestDirRecursiveReturnValue=$to_process_dir
return 1
else
echo "${message} ${to_process_dir}"
checkInputDestDirRecursive ${to_process_dir}
fi
}
echo `func1`
echo `func2`
func1
retValue=$?
echo "func1 retValue=$retValue"
retValue=`func2`
echo "func2 retValue=$retValue"
checkDirCore $(pwd) "指定类的查找目录不存在"
dir=${CheckInputDestDirRecursiveReturnValue}
echo "dir = ${dir}"
# 输出:
=======方法=======
func1 invoked
return value
func1 invoked
func1 retValue=24
func2 retValue=return value
scriptName=./syntax.sh paramsCount=2
目录存在 /Users/aron/git-repo/ShellLearning/helloshell
dir = /Users/aron/git-repo/ShellLearning/helloshell
复制代码
文件的读取可使用cat
命令结合for in
循环处理
注意:'\n'`,处理完成以后恢复旧值
echo "=======文件======="
file="data"
IFS_OLD=$IFS
IFS=$'\n'
for line in $(cat $file)
do
echo "${line}"
done
IFS=${IFS_OLD}
输出:
=======文件=======
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
复制代码
文件的读取可使用ls
命令结合for in
循环处理
echo "=======文件目录======="
function read_implement_file_recursively {
if [[ -d $1 ]]; then
for item in $(ls $1); do
itemPath="$1/${item}"
if [[ -d $itemPath ]]; then
# 目录
echo "处理目录 ${itemPath}"
read_implement_file_recursively $itemPath
else
# 文件
echo "处理文件 ${itemPath}"
fi
done
else
echo "err:不是一个目录"
fi
}
read_implement_file_recursively $(pwd)
输出:
=======文件目录=======
处理文件 /Users/aron/git-repo/ShellLearning/helloshell/data
处理目录 /Users/aron/git-repo/ShellLearning/helloshell/subfolder
处理文件 /Users/aron/git-repo/ShellLearning/helloshell/subfolder/data2
处理文件 /Users/aron/git-repo/ShellLearning/helloshell/syntax.sh
复制代码
使用输出重定向把内容输出到文件
>
输出重定向符号先清空文件而后把内容写入到文件中>>
输出重定向符号把内容追加写入到文件中此外能够结合其余命令实现排序、去重功能
sort
命令对文件内容以行做为单位排序uniq
命令对文件内容进行去重,以行为单位,通常须要结合sort
命令使用file="subfolder/data2"
destfile="subfolder/data2-p"
sort ${file} | uniq > ${destfile}
结果:
➜ helloshell git:(master) ✗ cat subfolder/data2
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
The quick brown
fox
jumps over the lazy dog.%
➜ helloshell git:(master) ✗ cat subfolder/data2-p
The quick brown
The quick brown fox jumps over the lazy dog.
fox
jumps over the lazy dog.
复制代码
Sed流编辑结合正则表达式能够方便的对文本文件进行查询、修改、删除、增长等操做
注意:osx系统自带的sed命令和标准的gun-sed使用方式上有些差异,因此如下篇幅所谈论到的sed都是标准的gun-sed,下面的这个脚本用户判断系统是否安装了gun-sed,若是没有回自动进行安装,完成以后须要用户执行显示的显示的命令配置下便可。
# 检测是否安装gun sed,mac 内置的sed会有些问题,因此须要安装gun sed
gunSedInstallCheck() {
# 检查是否安装gunsed
# mac安装gunSed http://blog.csdn.net/sun_wangdong/article/details/71078083
which_sed=`which sed`
echo $which_sed
echo "testresult = $(expr "$which_sed" : '.*/gnu-sed/')"
which_sed=`ls -al ${which_sed}`
echo $which_sed
echo "testresult = $(expr "$which_sed" : '.*/gnu-sed/')"
if [[ $(expr "$which_sed" : '.*/gnu-sed/') -gt 0 ]]; then
echo "检测到使用gun sed"
else
if [ ! `which brew` ]
then
echo 'Homebrew not found. Trying to install...'
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" \
|| exit 1
fi
echo 'Trying to install gun sed...'
brew install gnu-sed --with-default-names || exit 1
# 设置局部环境变量
echo "set PATH...."
source ./set-gun-sed-path.sh
echo "set PATH done"
echo "请手动执行命令,而后从新执行"
command="PATH=\"/usr/local/Cellar/gnu-sed/4.4/bin:\$PATH\""
echo $command
echo ""
exit 1
fi
}
复制代码
sed
命令功能繁多,因此这里只讲讲我在实战中使用到的,首先了解小sed命令的结构
sed -param operation/pattern/replacement/flags
查找对应的模式和匹配模式的替换内容
有4种可用的替换标记:
如下是injectContentShell#injectedContentShell.sh
脚本文件中的代码片断,使用a
操做吧内容添加到方法的开头
/^- \(.*\){$/
这部分是pattern
,匹配OC中方法的开始a\ '"$injected_content"'
这部分是operation
,注意其中插入内容的变量要使用双引号和单引号包含处理# 在匹配的行下面添加插入内容
sed -i '/^- \(.*\){$/{ a\ '"$injected_content"' }' ${file}
复制代码
如下是injectContentShell#injectedContentShell.sh
脚本文件中的代码片断,使用d
操做删除内容
sed -i '/'"$pattern_str"'/ { d }' ${file}
复制代码
如下是injectContentShell#RenameClasses.sh
脚本文件中的代码片断,使用s
操做替换内容,有如下几个要点
s/'"${original_class_name}"'/'"${result_class_name}"'/g
,使用s
操做,注意pattern
和replacement
中变量的处理方式,使用双引号、单引号双重包含,使用flag
为g
表示所有替换grep ${original_class_name} -rl ${pbxproj_dir}
,grep
命令查找${pbxproj_dir}
文件夹下全部出现${original_class_name}
内容的文件,-r
选项表示递归查找,-l
选项表示只显示匹配到的文件,返回的结果多是多个的。sed -i '{ s/'"${original_class_name}"'/'"${result_class_name}"'/g }' `grep ${original_class_name} -rl ${pbxproj_dir}`
sed -i '{ s/'"${original_class_name}"'/'"${result_class_name}"'/g }' `grep ${original_class_name} -rl ${class_name_replace_dir}`
复制代码
shell是面向过程的语言,不具有面向对象的特性,shell能够把部分功能独立分离出来,放在单独的脚本文件中,其余模块能够导入该脚本文件,使用其中的功能,这就是shell的伪面向对象
工具模块是包含了工具方法的模块,好比数学计算能够放在一个单独的文件中独立为一个模块,其余须要使用到的地方引入这个模块,使用其中定义的方法便可
Math.sh
保存了一些数学计算函数
#!/bin/bash
power(){
base=$1
exp=$2
result=1
for (( i = 0; i < $exp; i++ )); do
result=$[ $result * $base ];
done
echo $result
}
复制代码
其余模块使用. ./Math.sh
包含这个模块,能够调用其中定义的power方法
注意:. ./Math.sh
中.
是source
的简写,这里也能够写成source ./Math.sh
echo "=======模块======="
. ./Math.sh
result=$(power 3 5)
echo "3^5 = ${result}"
输出:
=======模块=======
3^5 = 243
复制代码
流程模块是包含了一些列操做的模块,能够向该模块传递参数,也能够有返回值。流程模块中有两个地方比较特别,一个是流程模块自己参数的处理方式和外部调用流程模块传入参数的方式
流程模块处理参数使用getopts
命令实现,getopts optionstring opt
其中optionstring
格式:i:o:
,i
和o
以后的:
表示指定i
选项和o
选项须要有参数,第一个:
表示忽略错误,使用case分支处理参数选项对应的参数值。
#### 参数解析
echo "参数>>${@}"
while getopts :i:o: opt
do
case "$opt" in
i) param_input_dir=$OPTARG
echo "Found the -i option, with parameter value $OPTARG"
;;
o) param_output_file=$OPTARG
echo "Found the -o option, with parameter value $OPTARG"
;;
*) echo "Unknown option: $opt";;
esac
done
echo "param_input_dir = ${param_input_dir}"
echo "param_output_file = ${param_output_file}"
复制代码
参数的传递和使用命令行的选项相似,能够在选项后面添加该选项的参数值
./GetAndStoreClasses.sh\
-i ${class_search_dir}\
-o ${cfg_file}
复制代码
下面定义的是一个流程模块的脚本文件,是injectContentShell#GetAndStoreClasses.sh
脚本文件中的代码片断,实现了生成重命名的类的配置脚本
功能,能够传递两个参数。
#!/bin/bash
########################
# 脚本功能:生成重命名的类的配置脚本
# 输入参数 -i 输入的文件夹
# 输入参数 -o 保存的文件
########################
####### 参数定义
param_input_dir=""
param_output_file=""
####### 参数解析
echo "参数>>${@}"
while getopts :i:o: opt
do
case "$opt" in
i) param_input_dir=$OPTARG
echo "Found the -i option, with parameter value $OPTARG"
;;
o) param_output_file=$OPTARG
echo "Found the -o option, with parameter value $OPTARG"
;;
*) echo "Unknown option: $opt";;
esac
done
echo "param_input_dir = ${param_input_dir}"
echo "param_output_file = ${param_output_file}"
####### 配置
# 属性黑名单配置文件
blacklist_cfg_file="$(pwd)/DefaultClassesBlackListConfig.cfg"
####### 数据定义
# 定义保存须要处理目标文件的数组
declare -a implement_source_file_array
declare -a implement_source_file_name_array
implement_source_file_count=0
# mark: p384
# 递归函数读取目录下的全部.m文件
function read_implement_file_recursively {
echo "read_implement_file_recursively"
if [[ -d $1 ]]; then
for item in $(ls $1); do
itemPath="$1/${item}"
if [[ -d $itemPath ]]; then
# 目录
echo "处理目录 ${itemPath}"
read_implement_file_recursively $itemPath
echo "处理目录结束====="
else
# 文件
echo "处理文件 ${itemPath}"
if [[ $(expr "$item" : '.*\.m') -gt 0 ]]; then
echo ">>>>>>>>>>>>mmmmmmm"
implement_source_file_array[$implement_source_file_count]=${itemPath}
class_name=${item//".m"/""};
implement_source_file_name_array[$implement_source_file_count]=${class_name}
implement_source_file_count=$[ implement_source_file_count + 1 ];
fi
echo ""
fi
done
else
echo "err:不是一个目录"
fi
}
post_implement_file_handle() {
local wirte_to_file=$1
# 写入文件中
echo "# 须要处理的类配置文件" > ${wirte_to_file}
for(( i=0;i<${#implement_source_file_name_array[@]};i++))
do
class_file_name=${implement_source_file_name_array[i]};
echo ${class_file_name} >> ${wirte_to_file}
done;
# 去重
wirte_to_file_bak="${wirte_to_file}.bak"
mv ${wirte_to_file} ${wirte_to_file_bak}
sort ${wirte_to_file_bak} | uniq > ${wirte_to_file}
# 过滤
mv ${wirte_to_file} ${wirte_to_file_bak}
echo "# Properties Configs Filtered" > ${wirte_to_file}
IFS_OLD=$IFS
IFS=$'\n'
# 上一行的内容
lastLine="";
for line in $(cat ${wirte_to_file_bak} | sed 's/^[ \t]*//g')
do
grep_result=$(grep ${line} ${blacklist_cfg_file})
category_judge_substring="\+"
if [[ ${#line} -le 6 ]] || [[ $(expr "$line" : '^#.*') -gt 0 ]] || [[ -n ${grep_result} ]] || [[ ${line} =~ ${category_judge_substring} ]]; then
# 长度小于等于六、注释内容的行、在黑名单中的内容、分类文件不处理
echo "less then 6 char line or comment line"
else
if [[ -n ${lastLine} ]]; then
# 上一行是非空白行
# 比较上一行内容是不是当前行的一部分,不是添加上一行
if [[ ${line} =~ ${lastLine} ]]; then
echo "${line} 和 ${lastLine} 有交集"
else
echo ${lastLine} >> ${wirte_to_file}
fi
fi
# 更新上一行
lastLine=${line}
fi
done
IFS=${IFS_OLD}
# 删除临时文件
rm -f ${wirte_to_file_bak}
}
read_implement_file_recursively ${param_input_dir}
post_implement_file_handle ${param_output_file}
复制代码
在另外一个模块中使用流程模块
# 获取须要重命名的类名称,保存到配置文件中
./GetAndStoreClasses.sh\
-i ${class_search_dir}\
-o ${cfg_file}
复制代码
下面是一个循环的输入和检测输入是不是合法目录的例子,是injectContentShell#FileUtil.sh
脚本文件中的代码片断
echo -n "请输入目录: "
是输入的提示,-n
表示不换行,用户的输入跟随在提示后面read path
把用户的输入内容保存在变量path中# 循环检测输入的文件夹
checkInputDestDirRecursive() {
echo -n "请输入目录: "
read path
if [[ -d $path ]]; then
CheckInputDestDirRecursiveReturnValue=$path
else
echo -n "输入的目录无效,"
checkInputDestDirRecursive
fi
}
复制代码
在脚本中可能会有使用菜单选项进行交互的场景,有如下几个要点
read -n 1 option
命令中用了-n选项来限制只读取一个字符。这样用户只须要输入一个数字,也不用按回车键,输入的内容保存在option
变量中clear
命令是用来清空命令行的屏幕的echo -e
-e 选项用来处理转义字符echo -en
-n 选项让光标处于同一行,用户的输入会显示在同一行while
循环获取用户的输入,在while
循环中使用case
分支处理不一样的操做如下脚本是injectContentShell#injectedContentShell.sh
文件中的一部分
function genMunu {
clear
echo
echo -e "\t\t\t选项菜单\n"
echo -e "\t1. 删除注入内容"
echo -e "\t2. 添加注入内容"
echo -e "\t0. Exit menu\n\n"
echo -en "\t\tEnter option: "
read -n 1 option
}
while [[ 1 ]]; do
genMunu
case $option in
0 )
echo ""
echo "Bye"
exit 0
;;
1 )
# 删除配置文件中注入的内容
removeInjectedContent
;;
2 )
# 添加配置文件中注入的内容
addInjectedContent
;;
h )
genMunu
;;
* )
echo "Wrong!!"
;;
esac
echo
echo -en "\n\n\tHit any key to continue"
read -n 1 line
done
复制代码