小记一次shellscript的麻烦
一、起因:
之前写过篇文章 文本分析实例 ,大致的内容就是对 “nginx的web服务器进行日志分析,删除不被访问的截图”。
二、规范:
1、脚本应该有完整的状态判断
set -b
一旦出现问题立刻回报执行状态。
exit
同于退出shell,并返回给定值。
2、[ ]
、( )
内容前后空格比较好,不容易出错。(多扯点)
一般 [ ]
是shell中 if、while 标准写法,(( ))
是 shell 中的 for 标准写法。然而 php if for while、javascipt if for while、java 等却使用 if( )
for()
这样的表达方法,Python 干脆不用。
另外{}
似乎在所有语言中都有“快”的意思,{}
内可以写更多的赋值、运算、显示等 “动作”。( 注意 '()' 一般内部是判定 )。Linux shell 中对 "${}" 还有好玩的地方:防止参数被扩展。
3、为了寻求可扩展和更改特性,一般要求给重复使用的命令或字符串赋值变量。
三、麻烦:
1、find 命令
log_filename=access.log-*.gz
log_lsfilename=`find $log_path -name "$log_filename" | wc -l` # 可以看到我给 $log_filename 加上了双引号
之前报错:find: paths must precede expression
翻译过来:目录必须优先于表达式
报错原因:因为没有把 * 加上双引号,此时的 find 命令 -name 后的 $log_filename(即 access.log-*.gz ) **被扩展具有多个文件名 **。
解决方案:-name 的匹配字符串一定要用单引号或双引号包住,防止发生扩展。
注意地方: 如果在 shell 中希望该命令执行完成以后赋值给变量需要使用 ``
(它是你键盘符号 ~ 下面那个) 更多参考点我
2、 if 条件语句
if [ $log_lsfilename -le 0 ];then # 看到我使用的是 [] 之前是 [[ ]]
之前报错:command not found
报错原因:使用不正确的判断隔断符号
- 正确的是使用
[ ]
,好处是和 shell 大多数流程控制统一,弊端是必须使用英文的判断(包括但不仅限于:-lt 小于 -le 小于等于 -gt 大于 -ge 大于等于 -eq 等于 -ne 不等于) - 还可以是使用
(( ))
,好处是可以使用数学的大于小于等于,弊端是记忆不方便有冲突很怪。
3、gunzip 命令
gunzip -f ${log_path}/$log_filename && printf "
done.
" # gunzip 加上了 -f 参数
报错无法重现,但这里提供 --help 帮助信息内容: force overwrite of output file and compress links
翻译内容:强制重写输出文件并压缩链接
报错原因:在终端需要使用 -f 参数已防止文件出现等待
注意地方:和gunzip无关。是${}这个是防止命令扩展,上文已经讲解过了。我想说的是多个变量加上字符串都可以直接打,千万不要加引号,系统会直接输出。
四、畅想与说几句:
其实还是蛮伤心的,原来不是这么写的。原本的思路是先判断是否存在日志的目录,再判断find有没有结果最后再执行。这样就会有个问题就是需要像python一样给前面的if语句pass指令,后面有位大神提醒我说 ";" 就像 python 中的 “pass” 一样。(当然其实在终端是一样的,但放到脚本里就会系统不认...btw:print 脚本也不认需要 printf)
反正把,写这种判断还是要有写思路的别把自己写傻了另外思路要广别写的太啰嗦,产生很多冗余代码。这样对阅读和重构都是不利的,最后送一句话:傻子都能写出机器能理解的代码,但写出人能理解的代码却不容易。