指定一个默认脚本解释器
“#!” 是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种Shell。他指明了当我们没有指定解释器的时候默认的解释器。
为什么建议要在首行加上脚本默认解释器,因为有的操作系统的默认解释器不是sh或者bash,比如SUSE Linux默认的是csh,不能通过 ./ 的方式执行bash或sh脚本。
我们常用sh和bash,这两种是最受欢迎的shell,脚本中写一种即可。如:
#!/bin/bash
我们可以用下面的命令查看本机支持的解释器
$ cat /etc/shells/bin/sh/bin/bash/sbin/nologin/bin/tcsh/bin/csh/bin/dash
添加脚本描述信息
在脚本的前面建议加上脚本描述信息,这样方便查看脚本的信息和有利于脚本的维护工作。
一般的描述信息有:
- 脚本的写作时间,作者,版权等
- 脚本的用途
- 脚本的注意事项
#!/bin/bash # ########################## # Version: 1.0 # Author: 快用大数据 # Create Date : 2021-01-01 # Name: start_all.sh # Description: This is a test shell script # ########################### # Version: 1.1 # Author: 快用大数据 # Create Date : 2021-01-01 # Name: start_all.sh # Description: Add a function at the bottom # ###########################
脚本文件命名有规范
- 脚本文件后缀用.sh,方便识别文件为shell脚本.
- 脚本名称可以根据执行频率、用途、业务分类等在名称中加入些关键字,可以让人顾名思义,对脚本有个认知,如:
如启动脚本:start_all.sh stop_all.sh start_tomcat.sh stop_tomcat.sh
如业务用途脚本:ods_tablename_daliy.sh, dw_tablename_monthly.sh
变量命名有规范
变量的基本命名法则:
- 统一用小写字母命名,如 DATE="20210101"
- 由词组组成的变量名与函数名用下划线连将词组连接,如 start_date="20210101",function_name()
- 过长的变量名可以用驼峰命名法命名
shell日志与回显
在开发过程中,写好业务代码的重要性不言而喻,同样的做好日志记录要非常重要,通过看日志,能够帮我们解决很多问题。
下面是一些日志要注意的信息:
1、 一些DEBUG级别的日志在脚本调试结束后需要关闭。
2、 日志输出要带时间
3、日志的输出推荐使用tee -a ${log_file}的方式,可以直接在main函数入口处添加日志输出
logfile="/var/log/debug.log"# define functionsfunction foo(){ echo "foo"}function oo(){ echo "oo"}# define main functionfunction main(){ echo "START DATE:" $(date +"%Y-%m-%d %H:%M:%S") foo oo echo "FINISH DATE:" $(date +"%Y-%m-%d %H:%M:%S")}# invoke main functionmain|tee -a ${logfile}
标准输出重定向到log文件中,标准错误打印在屏幕上
$ sh start_all.sh > /data/logs/hadoop/debug.log
shell 错误输出重定向到标准输出
$ sh start_all.sh > /data/logs/hadoop/debug.log 2>&1
标准输出和标准错误重定向到不同log文件中
$ sh start_all.sh 1>log.log 2>err.log
使用$()给变量赋值
尽量使用$()将命令的结果赋给变量,而不是用反引号
input_dir=/home/hadoopfiles=$(ls ${input_dir})for file in ${files};do echo ${file}done;
shell变量引用
很多人喜欢直接用$号加变量名引用该变量,建议使用${变量名}来引用变量,这样不容易出错和混淆。
date="20200101"logfile="/data/logs/hadoop/${date}/debug.log"echo ${logfile}
对比
date="20200101"logfile="/data/logs/hadoop/$date/debug.log"echo $logfile
shell脚本的执行方式
脚本的执行方式有好几种,但是还是建议用脚本解释器来执行脚本。
强烈推荐,用血的教训总结。我们的调度工具在升级后,会修改其工作目录下的所有文件的权限变成只有只读权限 (400),导致升级后所有用./执行的脚本全部不能执行。
$ sh start_all.sh
脚本的执行方式有以下几种:
1、工作目录执行
工作目录执行,指的是执行脚本时,先进入到脚本所在的目录(此时,称为工作目录),然后使用 ./脚本方式执行。前提是脚本有可执行的权限,如果没有会报没有权限错误。
$ ./start_all.sh在没有执行权限时要先加执行权限$ chmod +x ./start_all.sh$ ./start_all.sh
2、绝对路径执行
绝对路径中执行,指的是直接从根目录/到脚本目录的绝对路径。前提是脚本有可执行的权限,否则会报没有权限错误。
$ /home/hadoop/start_all.sh
3、sh执行
sh执行,指的是用脚本对应的sh或bash来接着脚本执行
$ sh start_all.sh
注意,若是以方法三的方式来执行,那么,可以不必事先设定shell脚本的执行权限,甚至都不用写shell文件中的第一行(指定bash路径)。因为方法三是将start_all.sh作为参数传给sh(bash)命令来执行的。这时不是start_all.sh自己来执行,而是被人家调用执行,所以不要执行权限。
4、shell环境执行
shell环境执行,指的是在当前的shell环境中执行,可以使用 . 接脚本 或 source 接脚本
$ . start_all.sh或$ source start_all.sh
shell要有异常处理
要判断一段代码是否出现了异常,一个最基本的判断就是对他返回值的判断。在shell中,我们往往规定0为正常,一切非0返回值则为不正常。但往往我们在写shell脚本的时候,忽略对于返回值的判断。我们看一个很基本的shell程序。
$?这个常量代表的就是上一段shell的返回值,看下面的例子:
#!/bin/shcd /home/xxxx/if [ "$?"= "0" ]; then rm -rf *else echo "cannot change directory" 1>&2 exit 1fi