程序员必备神器! Shell 脚本最佳实践

 2024-02-21 05:01:36  阅读 0

前言

由于工作需要,最近又开始编译shell脚本了。 虽然大部分命令都是我自己经常使用的,但是写成脚本的时候我总觉得它们很难看。 当我看别人写的剧本时,我总是觉得它们很难读。 毕竟shell脚本并不是一种严肃的编程语言。 它更像是一个用来混合不同程序供我们调用的工具。

因此,很多人在写作的时候都会思考该写在哪里。 基本上就像是一个很长的main函数,让人不忍直视。 同时,由于历史原因,shell有很多不同的版本,也有很多功能相同的命令需要我们做出选择,因此代码规范很难统一。

考虑到以上原因,我查了一些相关文档,发现其实很多人都考虑过这些问题,也产出了一些不错的文章,但还是有点零散。 因此,我把这些文章整理在这里,作为以后自己编写脚本的技术规范。

代码风格规范

从“蛇杖”开始

所谓的其实就是#开头的注释! 出现在许多脚本的第一行。 当我们不指定解释器时,它指定默认解释器。 一般来说,可能是这样的:

#!/bin/bash

当然,口译员有很多种。 除了bash之外,我们还可以使用下面的命令来查看本机支持的解释器:

$ cat /etc/shells
#/etc/shells: valid login shells
/bin/sh
/bin/dash
/bin/bash
/bin/rbash
/usr/bin/screen

当我们直接使用./a.sh来执行这个脚本时,如果没有,那么就会默认使用$SHELL指定的解释器,否则就会使用指定的解释器。

此方法是我们推荐的用法。

代码有注释

注释显然是常识,但我还是想强调一点,这在 shell 脚本中尤为重要。 因为很多单行shell命令不容易理解,没有注释的话维护起来会特别麻烦。

注解的意义不仅仅是解释使用,而是告诉我们要注意什么,就像a.

具体来说,对于shell脚本来说,注释一般包括以下部分:

参数应标准化

这个非常重要。 当我们的脚本需要接受参数时,我们首先要判断参数是否符合规范,并给出适当的回显,以方便用户了解参数的使用。

至少,至少,我们至少要确定参数的数量:

if [[ $# != 2 ]];then    
   echo "Parameter incorrect."    
   exit 1
fi

变量和幻数

一般我们会在一开始就定义一些重要的环境变量,以保证这些变量的存在。

source /etc/profile
export PATH=”/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin:/apps/bin/”

shell变量和环境变量_shell脚本添加环境变量_shell脚本环境变量设置

这种定义方法有很常见的用途。 最典型的应用是,当我们本地安装了很多java版本时,我们可能需要指定一个java来使用。 然后我们将在脚本开头重新定义和控制 PATH 变量。 同时,一段好的代码通常不会在代码中硬编码大量的“幻数”。 如果必须有的话,一般是一开始就定义为变量,然后调用的时候直接调用该变量,方便以后的修改。

缩进有规则

对于 shell 脚本来说,缩进是一个大问题。 因为很多需要缩进的地方(比如if、for语句)都不长,很多人懒得缩进,而且很多人不习惯使用函数,导致缩进功能被削弱。

事实上,正确的缩进非常重要,尤其是在编写函数时,否则我们在读取时很容易将函数体与直接执行的命令混淆。

常见的缩进方法有“软制表符”和“硬制表符”。

命名有标准

所谓命名规范主要包括以下几点:

编码要统一

编写脚本时,尽量使用UTF-8编码,可以支持中文等一些奇怪的字符。 不过,虽然我会写中文,但我还是尽量用英文写评论和日志。 毕竟很多机器还是不直接支持中文,打字可能会出现乱码。 这里需要特别注意的一点是,当我们使用utf-8编码编写shell脚本时,一定要注意utf-8是否有BOM。 默认情况下,UTF-8格式是通过在文件开头添加三个EF BB BF字节来判断的,但是在Linux中默认是没有BOM的。 因此,如果我们在写脚本的话,一定要注意将编码改为Utf-8无BOM。 一般可以使用++等编辑器进行更改。 否则在Linux下运行时,会识别前三个字符,导致一些错误提示无法识别命令。 当然,编写跨平台脚本时的另一个常见问题是不同的换行符。 默认是\r\n,在unix下是\n。 不过有两个小工具可以很方便的解决这个问题:,。

记得添加权限

虽然这是一个小点,但我个人经常忘记,没有执行权限,就无法直接执行,这就有点烦人了。 。 。

日志和回声

不用说,日志的重要性在大型项目中非常重要,因为它允许我们回溯并纠正错误。

如果这个脚本是供用户直接在命令行使用的,那么我们最好能够在执行过程中实时回显执行过程,方便用户控制。

有时为了提高用户体验,我们会给回声添加一些特殊效果,比如颜色、闪烁等,具体可以参考本文ANSI/VT100的介绍。

密码要删除

不要在脚本中硬编码密码,不要在脚本中硬编码密码,不要在脚本中硬编码密码。

重要的事情说三遍,尤其是当脚本托管在这样的平台上时。 。 。

太长,无法分支

调用某些程序时,参数可能会很长。 为了保证更好的阅读体验,我们可以使用反斜杠来分隔行:

./configure \
–prefix=/usr \
–sbin-path=/usr/sbin/nginx \
–conf-path=/etc/nginx/nginx.conf \

请注意反斜杠之前的空格。

编码细节规范

shell脚本环境变量设置_shell变量和环境变量_shell脚本添加环境变量

代码高效

使用命令时,必须了解该命令的具体方法。 尤其是当数据处理量较大时,必须时刻考虑该命令是否会影响效率。

例如,以下两个 sed 命令:

sed -n '1p' file
sed -n '1p;1q' file

它们的功能是相同的,都是获取文件的第一行。 但是第一个命令读取整个文件,而第二个命令只读取第一行。 当文件很大时,仅仅这样不同的命令就会造成效率上的巨大差异。

当然,这只是举个例子。 本例真正正确的用法应该是使用 head -n1 file 命令。 。 。

经常使用双引号

几乎所有专家都建议在使用“$”获取变量时添加双引号。

很多时候不加双引号会带来很多麻烦。 为什么? 举个例子:

#!/bin/sh
#已知当前文件夹有一个a.sh的文件
var="*.sh"
echo $var
echo "$var"

他的运行结果如下:

a.sh
*.sh

为什么会发生这种情况? 其实可以解释他执行了如下命令:

echo *.sh
echo "*.sh"

很多情况下,使用变量作为参数时,一定要注意上面的一点,仔细理解其中的区别。 上面只是一个非常小的例子。 在实际应用中,这个细节引发的问题实在是太多了。 。 。

巧妙利用main函数

我们知道像Java、C这样的编译型语言都会有函数入口。 这种结构使得代码非常可读。 我们知道哪些是直接执行的,哪些是函数。 但脚本不同。 脚本是解释性语言,直接从第一行执行到最后一行。 如果命令和函数混在一起,阅读起来会很困难。

使用过的朋友都知道,一个标准的脚本至少是这样的:

#!/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等命令。 其次,我们可以使用声明变量。 这些方法比使用全局定义更好。

函数返回值

使用函数的时候一定要注意。 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的值。 这个时候我们应该做什么呢?

比较的方法是这样的:

eval echo \$$VAR2

这是什么意思? 其实就是构造了一个字符串echo

这种用法确实可行,但是看起来很不舒服,也很难直观地理解。 我们不推荐它。 事实上,我们不建议使用 eval 命令。

更舒服的写法如下:

echo ${!VAR1}

可以通过添加 ! 来实现简单的间接引用。 变量名之前。

不过需要注意的是,使用上面的方法,我们只能获取值,不能赋值。 如果要赋值,就得老老实实用eval来处理:

VAR1=VAR2
eval $VAR1=233
echo $VAR2

巧用

所谓的,也可以看作是多行输入法,即“

如本站内容信息有侵犯到您的权益请联系我们删除,谢谢!!


Copyright © 2020 All Rights Reserved 京ICP5741267-1号 统计代码