写Bash脚本的一些规范小结


接触Linux已经4、5年了,也写了不少的shell脚本(虽然说都很简单),不过一直都没有写过比较大的项目,平时虽然会收集一些好的脚本,但也只是小知识点上的总结,缺少一个规范性的东西,就是“游击队”的感觉,如果再这么写下去,估计也很难成为“正规军”,水平也不会有实质性的提高,所以觉得给自己写shell脚本(以后可能还会有Python、PHP、Perl这些……)定下一个需要遵守的规范会对自己的成长有所帮助,于是就有了这篇文章。成长是一个积累的过程,愿越来越好!

写Bash脚本的一些规范小结:
0.添加 debug 标识{方便调试脚本,验证正确性}
Debug="N"
mail_to="[email protected] [email protected]"
[[ $Debug = 'Y' ]] && mail_to="[email protected]"
1.PATH设置
# find / -type d -iname "bin"
/usr/local/bin
/usr/bin
/bin
# find / -type d -iname "sbin"
/usr/local/sbin
/usr/sbin
/sbin

export PATH=$PATH:/usr/local/bin:/usr/bin:/bin:/sbin:/usr/sbin/:/usr/local/sbin
2.脚本所在目录、脚本名称
SCRIPT_SELF_PATH="$(cd "$(dirname "$0")"; pwd)"
SCRIPT_SELF_NAME="$(basename "$0")"

PROGNAME=`type $0 | awk '{print $3}'`  # search for executable on path
PROGDIR=`dirname $PROGNAME`            # extract directory of program
PROGNAME=`basename $PROGNAME`          # base name of program
3.根据上一个命令的返回值打印提示消息
if [ $? -eq 0 ]; then
    echo "INFO|$(date +'%Y-%m-%d %H:%M:%S')|${FUNCNAME[0]}|Succeed!"
else
    echo "ERROR|$(date +'%Y-%m-%d %H:%M:%S')|${FUNCNAME[0]}|Failed!"
    return 1
fi
4.文件[夹]不存在则新建
result_path="/root/tmp/result"
if [ ! -d "$result_path"]; then
    mkdir -p "$result_path"
fi

result_path="${HOME}/hostsList"
[ -d "$result_path" ] || mkdir -p "$result_path"
5.计算脚本的执行消耗时间
function func_show_cost_time() {
    local cost_all="$SECONDS"
    local cost_h=$((cost_all/3600))
    local cost_m=$((cost_all%3600/60))
    local cost_s=$((cost_all%60))
    echo "INFO|cost|$cost_all|$cost_h:$cost_m:$cost_s"
}
6.某一字符集的for循环
items="0123456789abcdefghijklmnopqrstuvwxyz"
i=""
for ((i=0;;i++)); do
    item=${items:$i:1}
    if [ -z "$item" ]; then
        break
    fi
    echo $item
    # Put command here
    if [ $? -ne 0 ]; then
        echo "ERROR|command execute failed"
        exit 1
    else
        echo "INFO|command execute succeed"
    fi
done
7.某些直接命令的使用
pgrep
readlink
exec_user=$(ps -o user --no-headers "$pid")
8.跳过空行/注释行
cat file.conf | grep -Ev "(^$|^#$)"
9.防止因为权限不够导致的错误
tmp=$(cat /etc/rsyslog.conf 2>/dev/null || sudo cat /etc/rsyslog.conf 2>/dev/null)
10.用test命令简化脚本
test "$cc" == "163_box" && echo "$notice_type" | grep -q "alert"
test $? -eq 0 && mail_cc="${mail_cc},[email protected]"

# http://www.ict.griffith.edu.au/anthony/info/shell/script.hints
11.根据文件的新旧程度移动到指定位置
tmp_file=$(mktemp -p ${HOME})
tmp_time=$(date -d "-2 days" +'%Y-%m-%d 00:00:05')
touch -d "$tmp_time" "$tmp_file"
find ${HOME} -maxdepth 1 -type f -iname "${HOSTNAME}*.txt" ! -newer "$tmp_file" -print0 | xargs -0 -I {} mv {} ${result_path}
rm -f $tmp_file
12.shell脚本在执行失败时立即退出
搜索关键字:
  • linux bash script exit on error
参考链接:
参考解答:
set -e    #add this to the second line of the bash script
exit 0/1/2/...
bash -e script_name.sh

=待续=

, , ,

《 “写Bash脚本的一些规范小结” 》 有 4 条评论

  1. 编写可靠 bash 脚本的一些技巧
    https://mp.weixin.qq.com/s/VmM_U4RefRBHwIw8NegC8Q
    `
    写过很多 bash 脚本的人都知道,bash 的坑不是一般的多。其实 bash 本身并不是一个很严谨的语言,但是很多时候也不得不用。以下总结了一些编写可靠的 bash 脚本的小 tips。

    0. set -x -e -u -o pipefail
    在写脚本时,在一开始(Shebang 之后)加上下面这一句,或者它的缩略版,能避免很多问题,更重要的是能让很多隐藏的问题暴露出来:
    set -xeuo pipefail

    1. 防止重叠运行
    在一些场景中,我们通常不希望一个脚本有多个实例在同时运行。比如用 crontab 周期性运行脚本时,有时不希望上一个轮次还没运行完,下一个轮次就开始运行了。这时可以用 flock 命令来解决。flock 通过文件锁的方式来保证独占运行,并且还有一个好处是进程退出时,文件锁也会自动释放,不需要额外处理。

    2. 意外退出时杀掉所有子进程
    我们的脚本通常会启动好多子脚本和子进程,当父脚本意外退出时,子进程其实并不会退出,而是继续运行着。如果脚本是周期性运行的,有可能发生一些意想不到的问题。

    3. timeout 限制运行时间

    4. 连续管道时,考虑使用 tee 将中间结果落盘,以便查问题
    `

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注