shell脚本遇到的一些坑

1,不同脚本共用同一个全局变量引发的血案

b脚本引用另一个a脚本,类似于C语言里面的 include 引用,C冲突了还好,有静态编译检查;但是 shell 脚本冲突了就甭想它给你提示,除非你目的就是要用a脚本的变量,否则脚本之间变量冲突产生的问题令人莫名其妙。这里也引出了 sh 的编程规范,尽量不用全局变量,函数里面变量尽量加 local 限制。

2,在管道里面exit 引发的血案

如果你认为只要在 shell 脚本里面执行了 exit 就会退出脚本,那你就太天真了。进一步来讲,如果你在管道里面 exit 错误状态码,然后在调用该脚本的地方,获取脚本的执行状态码,那你就等着抓狂吧。原因是:管道里面exit不会退出脚本,而仅是退出管道,然后在管道的下一条语句命令继续执行!

plus,用 while read line;do CMD done < ./t.txt  可以避免 while 管道 exit 不退出脚本的问题。

3,在管道里面使用全局变量的悲剧

如果你尝试在管道里面对某个变量赋值,然后在管道外面使用这个变量,对不起,你又采坑了。、

plus,这个同样可以用 while read line;do CMD done < ./t.txt  避免。

4,for循环中的全局变量

TEST=8

for(i=0;i<TEST;i++) 和 for((i=0;i<$TEST;i++)) 两种写法是同样的效果,前者不会语法报错。

5,shell的一些编写规范

错误处理:set -x -e -u -o pipefail

下面说明每个参数的作用,以及一些例外的处理方式 :

-x : 在执行每一个命令之前把经过变量展开之后的命令打印出来。

这个对于 debug 脚本、输出 Log 时非常有用。 正式运行的脚本也可以不加。

-e : 遇到一个命令失败(返回码非零)时,立即退出。

bash 跟其它的脚本语言最大的不同点之一,应该就是遇到异常时继续运行下一条命令。 这在很多时候会遇到意想不到的问题。加上 -e ,会让 bash 在遇到一个命令失败时,立即退出。

如果有时确实需要忽略个别命令的返回码,可以用 || true 。如:

some_cmd || true        # 即使some_cmd失败了,仍然会继续运行
some_cmd || RET=$?      # 或者可以这样来收集some_cmd的返回码,供后面的逻辑判断使用

但是在管道串起多条命令的情况下,只有最后一条命令失败时才会退出。如果想让管道中任意一条命令失败就退出,就要用后面提到的-o pipefail 了。

加-e 有时候可能会不太方便,动不动就退出。但觉得还是应该坚持所谓的fail-fast 原则,也就是有异常时停止正常运行,而不是继续尝试运行可能存在缺陷的过程。如果有命令可以明确忽略异常,那可以用上面提到的 || true 等方式明确地忽略之。

-u :试图使用未定义的变量,就立即退出。

如果在 bash 里使用一个未定义的变量,默认是会展开成一个空串。有时这种行为会导致问题,比如:

rm -rf $MYDIR/data

如果 MYDIR 变量因为某种原因没有赋值,这条命令就会变成 rm -rf /data 。 这就比较搞笑了。。 使用 -u 可以避免这种情况。

但有时候在已经设置了-u 后,某些地方还是希望能把未定义变量展开为空串,可以这样写:

${SOME_VAR:-}

#  bash变量展开语法,可以参考:
https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html

-o pipefail : 只要管道中的一个子命令失败,整个管道命令就失败。

pipefail 与-e 结合使用的话,就可以做到管道中的一个子命令失败,就退出脚本。

 防止重叠运行

# flock --wait 超时时间   -e 锁文件   -c "要执行的命令"
# 例如:
flock  --wait 5  -e "lock_myscript"  -c "bash myscript.sh"

意外退出时杀掉所有子进程

在 stackoverflow 上找到的一个方法,原理就是利用 trap 命令在脚本退出时 kill 掉它整个进程组。 把下面的代码加在脚本开头区,实测管用:

trap "trap - SIGTERM && kill -- -$$" SIGINT SIGTERM EXIT

不过如果父进程是用 SIGKILL (kill -9) 杀掉的,就不行了。因为 SIGKILL 时,进程是没有机会运行任何代码的。

+++++++++++++++++++++++++++附加几个基本概念+++++++++++++++++++++++++++++

1,shell状态码只能是 0~255 之间的整数

2,shell能处理的数据仅限于整数,如果一定要用浮点数,了解下bc工具

3,数值比较

4,字符串比较

要注意 > 和 < 两个操作符都要加转义,并且比较的依据是按ASCII字典为依据的。这和sort按系统设置比较不同。

5,文件判断

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值