背景

临上线前测试比较努力,遇到闪退或者其他问题,会把日志包打给我,由于app内存限制,目前每次打包都是1m大小,所以有时查找问题的上下文比较吃力。同时由于日志比较多,根据关键词过滤的需求越来越重要。

于是决定学写脚本完成这个任务,根据我的要求,工作流程应该是传入压缩包,根据后缀名解压,根据日期排序后合并成一个文件,按需过滤关键词。


先上代码

  1. #!/usr/bin/env bash
  2. # Created By Vanch at 2018/9/20
  3. printHelp() {
  4. echo "Uncompess log files from inputed zip"
  5. echo "Then Merge these logs to one file"
  6. echo "Supported file types: zip tar tar.gz tar.bz2"
  7. echo
  8. echo "Use -s for filtering socket result to socket.log"
  9. echo
  10. echo "Have fun!"
  11. }
  12. #如果没输入参数,就打印帮助信息
  13. if [ $# -eq 0 ]; then
  14. printHelp
  15. exit 0
  16. fi
  17. #把长选项转到短选项
  18. for arg in "$@"; do
  19. shift
  20. case "$arg" in
  21. "--help") set -- "$@" "-h" ;;
  22. "--version") set -- "$@" "-v" ;;
  23. "--list") set -- "$@" "-l" ;;
  24. *) set -- "$@" "$arg"
  25. esac
  26. done
  27. #获取短选项
  28. OPTIND=1
  29. printS=false;
  30. while getopts "dmksahvl" opt; do
  31. case $opt in
  32. h) #输入为help,就打印帮助信息
  33. printHelp
  34. exit 0;;
  35. l) #支持单独获取支持文件后缀列表
  36. echo "Supported file types: zip tar tar.gz tar.bz2"
  37. exit 0;;
  38. v) #支持查找版本号
  39. echo "1.0.0"
  40. exit 0;;
  41. s) #过滤Socket
  42. printS=true;;
  43. esac
  44. done
  45. #获得压缩包地址
  46. file=${!#}
  47. #如果不存在就退出
  48. if [ ! -f "$file" ]; then
  49. echo "File not exist!"
  50. exit 0;
  51. fi
  52. #获取压缩后缀
  53. fileName=`basename $file`
  54. suffix=${fileName#*.}
  55. #判断文件类型
  56. support=('tar','tar.gz','tar.bz2','zip')
  57. if [ -z `echo "${support[@]}" | grep -w "$suffix"` ] ; then
  58. echo "File type not support!"
  59. exit 0;
  60. fi
  61. #拼接文件夹地址
  62. fileDir=$(dirname $file)/${fileName%%.*}
  63. if [ -d $fileDir ]; then
  64. rm -rf $fileDir
  65. fi
  66. mkdir $fileDir
  67. cd $fileDir
  68. #解压文件
  69. case $suffix in
  70. 'tar')
  71. eval "tar xvf $file > /dev/null 2>&1";;
  72. 'tar.gz')
  73. eval "tar zxvf $file > /dev/null 2>&1";;
  74. 'tar.bz2')
  75. eval "tar jxvf $file > /dev/null 2>&1";;
  76. 'zip')
  77. eval "unzip -o $file > /dev/null 2>&1";;
  78. esac
  79. echo 'Uncompass Success!'
  80. #获取日志列表,按排序合并到一个日志
  81. mergeFile=./merge.log
  82. logCount=0
  83. #搜索com开头的日志,按日期排序,用?临时代替空格
  84. for logName in `ls | grep 'com' | sort -n | tr " " "?"`; do
  85. logName=${logName//'?'/' '}
  86. cat ./"$logName" >> $mergeFile
  87. ((logCount++))
  88. done
  89. #不存在日志就打断
  90. if [ $logCount -eq 0 ]; then
  91. echo "Log not exist!"
  92. exit
  93. fi
  94. echo 'Merge Success!'
  95. #打印socket
  96. if [ $printS = true ]; then
  97. cat $mergeFile | grep -i 'socket' >> ./socket.log
  98. echo 'Filter socket'
  99. fi

遇到的问题

查询了很多资料后写完了这个脚本,基本满足了我的需求,下面总结一下怎么解决遇到的问题。

使用环境

一开始学脚本时,书上都说#! /bin/bash,但是看项目中大神写的脚本,都是#!/usr/bin/env bash,有什么区别呢?

脚本用env启动的原因,是因为脚本解释器在linux中可能被安装于不同的目录,env可以在系统的PATH目录中查找。

同时,env还规定一些系统环境变量。

不同的系统,解释器的路径可能也不同,所以使用绝对路径是比较危险的方式。通过从环境中查找,可以保证兼容性。


获取选项

开发中我们经常用到命令,这些命令一般都配合选项达到不同的效果,比如最常用的ls -al,通过-a来指定结果包含隐藏文件,通过-l达到列表显示的效果。

通过查询相关资料,我发现获取选项普遍的做法是使用getopts命令,但是这个方法只能获取-h这种短选项,对于--help长选项就不行。

第一种办法是换成getopt命令,但是并不是每个系统都支持这个命令。具体使用和getopts类似,比如getopt -o ab:c -l a-long:b-long

第二种方法是把支持的长命令转成短命令,我使用的就是这种方式,相对来说比较容易理解,且case写的比较统一。通过shift取出参数,再set --的方式重写,最后OPTIND=1把指针指回第一个选项。


文件路径和文件后缀

按需求需要判断后缀名来解压,那么就需要判断tar.gz之类的问题。同时,如果传入的文件目录是隐藏目录,也会造成一定的障碍。我们假设传入文件路径为/a/.b/c.tar.gz

${param#pattern} 从param前面删除pattern的最小匹配

${param##pattern} 从param前面删除pattern的最大匹配

${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的方式来过滤结果获取文件名数组的最大问题是,如果文件名包含空格,那么前后会被分割成两个单元,导致处理比较困难。

比较讨巧的方法是临时用特殊符号代替空格,在使用时再替换回来。这种方法不会改变文件名,也不用写复杂的数组合并,比较符合简单的设计。

  1. tr " " "?"
  2. ${logName//'?'/' '}

总结

通过这次简单的脚本实验,对shell有了新的认识,及时记录遇到的问题,相信下次会更有印象。使用脚本,可以让工作更有效率,相信以后也会越用越多。

初试Shell脚本的更多相关文章

  1. 第一个shell脚本

    打开文本编辑器,新建一个文件,扩展名为sh(sh代表shell),扩展名并不影响脚本执行,见名知意就好. #!/bin/bash echo "Hello World !" &quo ...

  2. 使用C#给Linux写Shell脚本

    在这个逼格决定人格,鄙视链盛行的年头,尤其是咱们IT界,请问您今天鄙视与被鄙视的次数分别是多少?如果手中没有一点压箱的本事,那就只有看的份了.今天我们也要提升下自己的格调,学习些脑洞大开的东西,学完之 ...

  3. shell脚本规划化模板

    shell脚本规划化模板 Linux运维过程中,shell脚本是不可缺少的工具,但是每个运维人员编程的习惯都不一样,很多时候就是实现某个功能,写出来的脚本都是烂七八糟的.脚本必须规范化,应该从以后几个 ...

  4. Shell脚本编程30分钟入门

    Shell脚本编程30分钟入门 转载地址: Shell脚本编程30分钟入门 什么是Shell脚本 示例 看个例子吧: #!/bin/sh cd ~ mkdir shell_tut cd shell_t ...

  5. Linux Shell脚本逻辑操作符简介

    在写程序时,会用到条件判断,测试条件是否成立.很多时候,判断条件是多个的,这个时候需要用到逻辑操作符.shell脚本中常用的有哪些逻辑操作符呢? 1.逻辑与: -a 格式: conditon1 -a ...

  6. Linux shell脚本编程(三)

    Linux shell脚本编程 流程控制: 循环语句:for,while,until while循环: while CONDITION; do 循环体 done 进入条件:当CONDITION为“真” ...

  7. Linux shell脚本编程(二)

    Linux shell脚本编程(二) 练习:求100以内所有偶数之和; 使用至少三种方法实现; 示例1: #!/bin/bash # declare -i sum=0 #声明一个变量求和,初始值为0 ...

  8. Linux shell脚本编程(一)

    Linux shell脚本编程: 守护进程,服务进程:启动?开机时自动启动: 交互式进程:shell应用程序 广义:GUI,CLI GUI: CLI: 词法分析:命令,选项,参数 内建命令: 外部命令 ...

  9. 详解Linux交互式shell脚本中创建对话框实例教程_linux服务器

    本教程我们通过实现来讲讲Linux交互式shell脚本中创建各种各样对话框,对话框在Linux中可以友好的提示操作者,感兴趣的朋友可以参考学习一下. 当你在终端环境下安装新的软件时,你可以经常看到信息 ...

随机推荐

  1. IOS和安卓WEB页面,input输入框被软键盘遮挡解决方法

    本来以为这问题就只有ios才有,身边也没有android机测试,网上一搜,貌似有这个问题的还不少.最后把各种解决方法试了一边,貌似没什么用. 最后是这样解决的: setInterval(functio ...

  2. [AHOI2005]矿藏编码

    嘟嘟嘟 这道题题面我是看了小半天才懂(太菜了),然后就发现好水啊. 只要维护一个栈,存的是t,代表当前的正方形是2t * 2t的,然后从头开始扫序列,如果遇到2,就把栈顶元素取出来,然后放进去四个t ...

  3. web常用的正则表达式

    1.    平时做网站经常要用正则表达式,下面是一些讲解和例子,仅供大家参考和修改使用: 2.    "^\d+$" //非负整数(正整数 + 0) 3.    "^[0 ...

  4. Redis(五)主从复制

    本文转载自编程迷思,原文链接 深入学习Redis(3):主从复制 前言 在前面的两篇文章中,分别介绍了Redis的内存模型和Redis的持久化. 在Redis的持久化中曾提到,Redis高可用的方案包 ...

  5. SQLite加密方式 [转]

    关于SQLite SQLite是一个轻量的.跨平台的.开源的数据库引擎,它的在读写效率.消耗总量.延迟时间和整体简单性上具有的优越性,使其成为移动平台数据库的最佳解决方案(如iOS.Android). ...

  6. asp.net core合并压缩资源文件(转载)

    在asp.net core中使用BuildBundlerMinifier合并压缩资源文件 在asp.net mvc中可以使用Bundle来压缩合并css,js 不知道的见:http://www.cnb ...

  7. Activiti6.0 工作流引擎 websocket即时聊天发图片文字 好友群组 SSM源码

    即时通讯:支持好友,群组,发图片.文件,消息声音提醒,离线消息,保留聊天记录 (即时聊天功能支持手机端,详情下面有截图) 工作流模块---------------------------------- ...

  8. OO——求导作业总结

    目录 OO--求导作业总结 程序结构的分析 第一次作业 第二次作业 第三次作业 对多项式合法性判断的讨论 程序bug的分析 未通过的互测bug bug的位置与程序结构的关系 继承和接口的使用 互测 手 ...

  9. Angular7教程-01-Angular开发环境配置

    本教程基于angular7(2018-11-04) 1. 安装node.js 下载地址: http://nodejs.cn/download/ 下载对应自己操作系统的版本安装即可. 2.安装 angu ...

  10. C++ 函数的二义性

    函数二义性是一种编译时发生的错误,造成二义性调用的原因 是在函数匹配时两个或多个函数提供的匹配一样好,编译时找 不到唯一的最佳匹配. 列: #include <iostream> usin ...