临上线前测试比较努力,遇到闪退或者其余问题,会把日志包打给我,因为app内存限制,目前每次打包都是1m大小,因此有时查找问题的上下文比较吃力。同时因为日志比较多,根据关键词过滤的需求愈来愈重要。linux
因而决定学写脚本完成这个任务,根据个人要求,工做流程应该是传入压缩包,根据后缀名解压,根据日期排序后合并成一个文件,按需过滤关键词。shell
#!/usr/bin/env bash
# Created By Vanch at 2018/9/20
printHelp() {
echo "Uncompess log files from inputed zip"
echo "Then Merge these logs to one file"
echo "Supported file types: zip tar tar.gz tar.bz2"
echo
echo "Use -s for filtering socket result to socket.log"
echo
echo "Have fun!"
}
#若是没输入参数,就打印帮助信息
if [ $# -eq 0 ]; then
printHelp
exit 0
fi
#把长选项转到短选项
for arg in "$@"; do
shift
case "$arg" in
"--help") set -- "$@" "-h" ;;
"--version") set -- "$@" "-v" ;;
"--list") set -- "$@" "-l" ;;
*) set -- "$@" "$arg"
esac
done
#获取短选项
OPTIND=1
printS=false;
while getopts "dmksahvl" opt; do
case $opt in
h) #输入为help,就打印帮助信息
printHelp
exit 0;;
l) #支持单独获取支持文件后缀列表
echo "Supported file types: zip tar tar.gz tar.bz2"
exit 0;;
v) #支持查找版本号
echo "1.0.0"
exit 0;;
s) #过滤Socket
printS=true;;
esac
done
#得到压缩包地址
file=${!#}
#若是不存在就退出
if [ ! -f "$file" ]; then
echo "File not exist!"
exit 0;
fi
#获取压缩后缀
fileName=`basename $file`
suffix=${fileName#*.}
#判断文件类型
support=('tar','tar.gz','tar.bz2','zip')
if [ -z `echo "${support[@]}" | grep -w "$suffix"` ] ; then
echo "File type not support!"
exit 0;
fi
#拼接文件夹地址
fileDir=$(dirname $file)/${fileName%%.*}
if [ -d $fileDir ]; then
rm -rf $fileDir
fi
mkdir $fileDir
cd $fileDir
#解压文件
case $suffix in
'tar')
eval "tar xvf $file > /dev/null 2>&1";;
'tar.gz')
eval "tar zxvf $file > /dev/null 2>&1";;
'tar.bz2')
eval "tar jxvf $file > /dev/null 2>&1";;
'zip')
eval "unzip -o $file > /dev/null 2>&1";;
esac
echo 'Uncompass Success!'
#获取日志列表,按排序合并到一个日志
mergeFile=./merge.log
logCount=0
#搜索com开头的日志,按日期排序,用?临时代替空格
for logName in `ls | grep 'com' | sort -n | tr " " "?"`; do
logName=${logName//'?'/' '}
cat ./"$logName" >> $mergeFile
((logCount++))
done
#不存在日志就打断
if [ $logCount -eq 0 ]; then
echo "Log not exist!"
exit
fi
echo 'Merge Success!'
#打印socket
if [ $printS = true ]; then
cat $mergeFile | grep -i 'socket' >> ./socket.log
echo 'Filter socket'
fi
复制代码
查询了不少资料后写完了这个脚本,基本知足了个人需求,下面总结一下怎么解决遇到的问题。数组
一开始学脚本时,书上都说#! /bin/bash
,可是看项目中大神写的脚本,都是#!/usr/bin/env bash
,有什么区别呢?bash
脚本用env启动的缘由,是由于脚本解释器在linux中可能被安装于不一样的目录,env能够在系统的PATH目录中查找。 同时,env还规定一些系统环境变量。app
不一样的系统,解释器的路径可能也不一样,因此使用绝对路径是比较危险的方式。经过从环境中查找,能够保证兼容性。socket
开发中咱们常常用到命令,这些命令通常都配合选项达到不一样的效果,好比最经常使用的ls -al
,经过-a
来指定结果包含隐藏文件,经过-l
达到列表显示的效果。测试
经过查询相关资料,我发现获取选项广泛的作法是使用getopts
命令,可是这个方法只能获取-h
这种短选项,对于--help
长选项就不行。ui
第一种办法是换成getopt
命令,可是并非每一个系统都支持这个命令。具体使用和getopts
相似,好比getopt -o ab:c -l a-long:b-long
spa
第二种方法是把支持的长命令转成短命令,我使用的就是这种方式,相对来讲比较容易理解,且case写的比较统一。经过shift
取出参数,再set --
的方式重写,最后OPTIND=1
把指针指回第一个选项。设计
按需求须要判断后缀名来解压,那么就须要判断tar.gz
之类的问题。同时,若是传入的文件目录是隐藏目录,也会形成必定的障碍。咱们假设传入文件路径为/a/.b/c.tar.gz
。
{param##pattern} 从param前面删除pattern的最大匹配
{param%%pattern} 从param后面删除pattern的最大匹配
若是按照${fileName##*.}
来截取,那么只能拿到gz
。 若是按照${fileName#*.}
来截取,拿到的又是b/c.tar.gz
。那怎么办呢?
好在有dirname
能够直接获取文件路径,basename
拿到文件名,单独对文件名进行${fileName#*.}
就能够拿到tar.gz
了。
执行解压命令时,会打印解压步骤,通常来讲也须要显示,那若是咱们不想要打印出来呢?有一个办法就是在命令以后加上> /dev/null 2>&1
/dev/null :表明空设备文件
> :表明重定向到哪里,例如:echo "123" > /home/123.txt
1 :表示stdout标准输出,系统默认值是1,因此">/dev/null"等同于"1>/dev/null"
2 :表示stderr标准错误
& :表示等同于的意思,2>&1,表示2的输出重定向等同于1
因此含义就是把命令输出结果和错误输出重定向,使得输出不在当前屏幕显示,因为null比较特殊,向这个文件输入等于进入黑洞,所以达到效果。
使用ls | grep
的方式来过滤结果获取文件名数组的最大问题是,若是文件名包含空格,那么先后会被分割成两个单元,致使处理比较困难。
比较讨巧的方法是临时用特殊符号代替空格,在使用时再替换回来。这种方法不会改变文件名,也不用写复杂的数组合并,比较符合简单的设计。
tr " " "?"
${logName//'?'/' '}
复制代码
经过此次简单的脚本实验,对shell有了新的认识,及时记录遇到的问题,相信下次会更有印象。使用脚本,可让工做更有效率,相信之后也会越用越多。