登录  | 加入社区

黑狼游客您好!登录后享受更多精彩

只需一步,快速开始

新浪微博登陆

只需一步, 快速开始

查看: 862|回复: 0

想要编写 Shell 脚本的最佳实践?看这篇就够了~

[复制链接]

216

主题

1

帖子

0

现金

黑狼菜鸟

Rank: 1

积分
0
发表于 2017-11-22 23:06:35 | 显示全部楼层 |阅读模式 来自 广东汕头


点击蓝色字关注"CU技能社区" 一起玩耍哦~

作者:Myths
原文地点:http://kb.cnblogs.com/page/574767/




媒介

由于工作必要,近来重新开始拾掇 shell 脚本。固然绝大部门下令本身平常也常常利用,但是在写成脚本的时间总以为写的很丢脸。而且当我在看其他人写的脚本的时间,总以为难以阅读。究竟 shell 脚本这个东西不算是端庄的编程语言,他更像是一个工具,用来杂糅差别的步伐供我们调用。因此许多人在写的时间也是想到那里写到那里,根本上都像是一段超长的 main 函数,不忍直视。同时,由于汗青缘故原由,shell 有许多差别的版本,而且也有许多有雷同功能的下令必要我们举行弃取,以至于代码的规范很难同一。

思量到上面的这些缘故原由,我查阅了一些相干的文档,发现这些题目实在许多人都思量过,而且也形成了一些不错的文章,但是照旧有点零星。因此我就在这里把这些文章轻微整理了一下,
作为以后我本身写脚本的技能规范。


S07O7gAazWt7705d.jpg




 代码风格规范 





开头有 “蛇棒”所谓 shebang 实在就是在许多脚本的第一行出现的以”#!” 开头的解释,他指明白当我们没有指定表明器的时间默认的表明器,一样平常大概是下面如许:


#!/bin/bas固然,表明器有许多种,除了 bash 之外,我们可以用下面的下令检察本机支持的表明器:


#!/bin/$ cat /etc/shells      #/etc/shells: valid login shells      /bin/sh      /bin/dash      /bin/bash      /bin/rbash      /usr/bin/screen当我们直接利用./a.sh 来实行这个脚本的时间,假如没有 shebang,那么它就会默认用 $SHELL 指定的表明器,否则就会用 shebang 指定的表明器。



不外,上面这种写法大概不太具备顺应性,一样平常我们会用下面的方式来指定:

#!/usr/bin/env bash这种方式是我们保举的利用方式。





代码有解释

解释,显然是一个知识,不外这里照旧要再夸大一下,这个在 shell 脚本里尤为紧张。由于许多单行的 shell 下令不是那么浅近易懂,没有解释的话在维护起来会让人尤其的头大。
解释的意义不但在于表明用途,而在于告诉我们留意事项,就像是一个 README。
详细的来说,对于 shell 脚本,解释一样平常包罗下面几个部门:




  • shebang
  • 脚本的参数
  • 脚本的用途
  • 脚本的留意事项
  • 脚本的写作时间,作者,版权等
  • 各个函数前的阐明解释
  • 一些较复杂的单行下令解释





参数要规范

这一点很紧张,当我们的脚本必要担当参数的时间,我们肯定要先判定参数是否合乎规范,并给出符合的回显,方便利用者相识参数的利用。

最少,最少,我们至少得判定下参数的个数吧:

if [[ $# != 2 ]];then       echo "Parameter incorrect."       exit 1  
fi
变量和魔数

一样平常环境下我们会将一些紧张的情况变量界说在开头,确保这些变量的存在。

source /etc/profileexport PATH=”/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin:/apps/bin/”这种界说方式有一个很常见的用途,最典范的应用就是,当我们当地安装了许多 java 版本时,我们大概必要指定一个 java 来用。那么这时我们就会在脚本开头重新界说 JAVA_HOME 以及 PATH 变量来举行控制。



同时,一段好的代码通常是不会有许多硬编码在代码里的 “魔数” 的。假如肯定要有,通常是用一个变量的情势界说在开头,然后调用的时间直接调用这个变量,如许方便日后的修改。


缩进有规矩

对于 shell 脚本,缩进是个大题目。由于许多必要缩进的地方 (好比 if,for 语句) 都不长,全部许多人都懒得去缩进,而且许多人不风俗用函数,导致缩进功能被弱化。
实在精确的缩进是很紧张的,尤其是在写函数的时间,否则我们在阅读的时间很轻易把函数体跟直接实行的下令搞混。


常见的缩进方法重要有”soft tab” 和”hard tab” 两种。




  • 所谓 soft tab 就是利用 n 个空格举行缩进 (n 通常是 2 或 4)
  • 所谓 hard tab 固然就是指真实的”\t” 字符
    这里不去撕哪种方式最好,只能说各有各的优劣。反正我风俗用 hard tab。
    对于 if 和 for 语句之类的,我们最好不要把 then,do 这些关键字单独写一行,如许看上去比力丑。。。





定名有尺度

所谓定名规范,根本包罗下面这几点:



  • 文件名规范,以. sh 末端,方便辨认
  • 变量名字要有寄义,不要拼错
  • 同一定名风格,写 shell 一样平常用小写字母加下划线





编码要同一在写脚本的时间只管利用 UTF-8 编码,可以或许支持中文等一些奇希奇怪的字符。不外固然能写中文,但是在写解释以及打 log 的时间照旧只管英文,究竟许多呆板照旧没有直接支持中文的,打出来大概会有乱码。

这里还尤其必要留意一点,就是当我们是在 windows 下用 utf-8 编码来写 shell 脚本的时间,肯定要留意这个 utf-8 是否是有 BOM 的。默认环境下 windows 判定 utf-8 格式是通过在文件开头加上三个 EF BB BF 字节来判定的,但是在 Linux 中默认是无 BOM 的。因此假如我们是在 windows 下写脚本的时间,肯定要留意将编码改成 Utf-8 无 BOM,一样平常用 notepad++ 之类的编辑器都能改。否则,在 Linux 下运行的时间就会辨认到开头的三个字符,从而报一些无法辨认下令的错。


权限记得加

这一点固然很小,但是我个人却常常忘记,不加实行权限会导致无法直接实行,有点讨厌。。。




日记和回显

日记的紧张性不必多说,可以或许方便我们转头纠错,在大型的项目里黑白常紧张的。
假如这个脚本是供用户直接在下令行利用的,那么我们最好还要可以或许在实行时及时回显实行过程,方便用户掌控。


有时间为了进步用户体验,我们会在回显中添加一些殊效,好比颜色啊,闪耀啊之类的,详细可以参考 ANSI/VT100 Control sequences 这篇文章的先容。





暗码要移除

不要把暗码硬编码在脚本里,不要把暗码硬编码在脚本里,不要把暗码硬编码在脚本里。

紧张的事变说三遍,尤其是当脚本托管在雷同 Github 这类平台中时。。。





太长要分行

在调用某些步伐的时间,参数大概会很长,这时间为了包管较好的阅读体验,我们可以用反斜杠来分行:

./configure \   –prefix=/usr \   –sbin-path=/usr/sbin/nginx \   –conf-path=/etc/nginx/nginx.conf \留意在反斜杠前有个空格。



 编码细节规范 





代码有服从

在利用下令的时间要相识下令的详细做法,尤其当数据处置惩罚量大的时间,要时候思量该下令是否会影响服从。

好比下面的两个 sed 下令:

sed -n '1p' filesed -n '1p;1q' file他们的作用一样,都是获取文件的第一行。但是第一条下令会读取整个文件,而第二条下令只读取第一行。当文件很大的时间,仅仅是如许一条下令不一样就会造成巨大的服从差别。



固然,这里只是为了举一个例子,这个例子真正精确的用法应该是利用 head -n1 file 下令。。。




勤用双引号

险些全部的大佬都保举在利用”$” 来获取变量的时间最好加上双引号。

不加上双引号在许多环境下都会造成很大的贫苦,为什么呢?举一个例子:

#!/bin/sh   #已知当前文件夹有一个a.sh的文件   var="*.sh"  
echo $var  
echo "$var"
他的运行效果如下:

a.sh*.sh为啥会如许呢?实在可以表明为他实行了下面的下令:

echo *.shecho "*.sh"在许多环境下,在将变量作为参数的时间,肯定要留意上面这一点,细致领会此中的差别。上面只是一个非常小的例子,现实应用的时间由于这个细节导致的题目着实是太多了。。。


巧用 main 函数

我们知道,像 java,C 如许的编译型语言都会有一个函数入口,这种布局使得代码可读性很强,我们知道哪些直接实行,那些是函数。但是脚本不一样,脚本属于表明性语言,从第一行直接实行到末了一行,假如在这当中下令与函数糅杂在一起,那就非常难读了。

用 python 的朋侪都知道,一个合乎尺度的 python 脚本大要上至少是如许的:

#!/usr/bin/env python   def func1():       pass   def func2():       pass   if __name__=='__main__':       func1()       func2()他用一个很奇妙的方法实现了我们风俗的 main 函数,使得代码可读性更强。

在 shell 中,我们也有雷同的小本领:

#!/usr/bin/env bash   func1(){       #do sth   }   func2(){       #do sth   }   main(){       func1       func2   }   main "$@"

我们可以接纳这种写法,同样实现雷同的 main 函数,使得脚本的布局化水平更好。
思量作用域



shell 中默认的变量作用域都是全局的,好比下面的脚本:

#!/usr/bin/env bash   var=1
func(){       var=2
  }   func   echo $var
他的输出效果就是 2 而不是 1,如许显然不符合我们的编码风俗,很轻易造成一些题目。



因此,相比直接利用全局变量,我们最好利用 local readonly 这类的下令,其次我们可以利用 declare 来声明变量。这些方式都比利用全局方式界说要好。




函数返回值

在利用函数的时间肯定要留意,shell 中函数的返回值只能是整数,估计是由于一样平常环境下一个函数的返回值通常表现这个函数的运行状态,以是一样平常都是 0 大概是1就够了,因此就计划成了如许。不外,假如非得想通报字符串,也可以通过下面变通的方法:

func(){       echo "2333"   }   res=$(func)   echo "This is from $res."如许,通过 echo 大概 print 之类的就可以做到传一些额外参数的目标。





间接引用值

什么叫间接引用?好比下面这个场景:

VAR1="2323232"
VAR2="VAR1"
我们有一个变量 VAR1,又有一个变量 VAR2,这个 VAR2 的值是 VAR1 的名字,那么我们如今想通过 VAR2 来获取 VAR1 的值,这时间应该怎么办呢?



比力土鳖的方法是如许:

echo ${!VAR1}这个用法简直可行,但是看起来非常的不惬意,很难只管的去明白,我们并不保举。而且究竟上我们自己就不保举利用 eval 这个下令。

比力惬意的写法是下面如许:

echo ${!VAR1}通过在变量名前加一个! 就可以做到简朴的间接引用了。



不外必要留意的是,用上面的方法,我们只可以或许做到取值,而不能做到赋值。
巧用 heredocs




<span style="font-size: 14px;">所谓 heredocs,也可以算是一种多行输入的方法,即在”/etc/rsyncd.conf




上一篇:学好Shell必备知识
下一篇:Android平台下Shell脚本现实开辟场景应用
您需要登录后才可以回帖 登录 | 加入社区

本版积分规则

 

QQ|申请友链|小黑屋|手机版|Hlshell Inc. ( 豫ICP备16002110号-5 )

GMT+8, 2024-5-15 18:09 , Processed in 0.061877 second(s), 47 queries .

HLShell有权修改版权声明内容,如有任何爭議,HLShell將保留最終決定權!

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表