脚本错误定位

脚本错误定位

常见错误

编写 Shell 脚本的时候,一定要考虑到命令失败的情况,否则很容易出错。

#! /bin/bash

dir_name=/path/not/exist

cd $dir_name
rm *

上面脚本中,如果目录 $dir_name 不存在,cd $dir_name 命令就会执行失败。这时,就不会改变当前目录,脚本会继续执行下去,导致 rm * 命令删光当前目录的文件。

如果改成下面的样子,也会有问题。

cd $dir_name && rm *

上面脚本中,只有 cd $dir_name 执行成功,才会执行 rm *。但是,如果变量 $dir_name 为空,cd 就会进入用户主目录,从而删光用户主目录的文件。

下面的写法才是正确的。

[[ -d $dir_name ]] && cd $dir_name && rm *

上面代码中,先判断目录 $dir_name 是否存在,然后才执行其他操作。

如果不放心删除什么文件,可以先打印出来看一下。

[[ -d $dir_name ]] && cd $dir_name && echo rm *

上面命令中,echo rm * 不会删除文件,只会打印出来要删除的文件。

bash-x 参数

bash-x 参数可以在执行每一行命令之前,打印该命令。一旦出错,这样就比较容易追查。

下面是一个脚本 script.sh

# script.sh
echo hello world

加上 -x 参数,执行每条命令之前,都会显示该命令。

$ bash -x script.sh
+ echo hello world
hello world

上面例子中,行首为 + 的行,显示该行是所要执行的命令,下一行才是该命令的执行结果。

其实这个就是 set -x 的效果,这命令我们在《set 命令和 shopt 命令》的 set -x 小节学习过

环境变量

有一些环境变量常用于错位 u 定位,我们可以用这些变量来手动记录错误日志

简单实践如下:

创建脚本 shell2.sh

#!/usr/bin/env bash

function shell_fun2(){
    echo =========================== 
    echo "${LINENO}" 
    echo "${BASH_SOURCE[@]}" 
    echo "${BASH_LINENO[@]}" 
    echo "${FUNCNAME[@]}" 
}

shell1.sh

#!/usr/bin/env bash

function shell_fun1(){
    echo =========================== 
    echo "${LINENO}" 
    echo "${BASH_SOURCE[@]}" 
    echo "${BASH_LINENO[@]}" 
    echo "${FUNCNAME[@]}" 
    shell_fun2
}

main.sh

#!/usr/bin/env bash

# 引用其他脚本
. ./shell1.sh
. ./shell2.sh

shell_fun1

赋权后执行 main.sh

$ ./main.sh 
===========================
5
./shell1.sh ./main.sh
6 0
shell_fun1 main
===========================
5
./shell2.sh ./shell1.sh ./main.sh
9 6 0
shell_fun2 shell_fun1 main

直接看 shell_fun2 的输出

BASH_SOURCE:main.sh 调用 shell1.shshell1.sh 调用 shell2.sh

BASH_LINENO:在交互式 shell 中调用 main.sh 为第 0 行(约定),main.sh 调用 shell1.sh,是在第 6 行,注释不算行,shell1.sh 调用 shell2.sh,是在第 9 行。

FUNCNAME:main 脚本调用 shell_fun1,shell_fun1 调用 shell_fun2。