Some tips for bash scripting

最近几天写了一些 bash 脚本,又有些心得,记录一下。

获取当前路径的绝对路径

比较常见的需求可能是获取相对路径,这样方便程序复制到其他目录也可以运行。使用 $(dirname $0) 就可以获取相对路径,不过这里说的是绝对路径。

其实也简单,相对路径加上当前目录,那不就是绝对路径么。不过是,有时候 $(dirname $0) 取到的也可能是绝对路径(一般期望相对路径的程序也能跑通,所以不大关心)。

可以用下面的做法,大意是先判断一下获取到的路径是不是 / 开头,如果是,那就不处理,如果不是,那就把当前的路径附加上去得到一个绝对路径。

PG_DIR="$(dirname $0)/../"

echo "$PG_DIR" | grep -q ^/

if [ $? -ne 0 ];then
        PG_DIR="$(pwd)/$PG_DIR"
fi

使用 getopt 获取命令行参数

获取参数比较常见的做法是取 $1 $2 这些,不过不太专业,这里说的是类似于 --prefix=/path/to/install -v 这种。

bash 本身提供了一个内部命令 getopts 来做这个事情,不过那个只能支持 short_opts,就是类似 -v 这种,不支持长的。

getopt 是一个 GNU 程序,他支持 long_opts。下面是个例子。代码基本来自网上。

ARGS=$(getopt -a -o h -l initdb::,help -- "$@")
[ $? -ne 0 ] && usage

eval set -- "${ARGS}" 

while true
do
        case $1 in
                --initdb)
                        initdb $2
                        ;;
                -h|--help)
                        usage;
                        ;;
                --)
                        shift
                        break
                        ;;
        esac
        shift
done

解释一下上面的参数的含义:

  • -o 参数指定的就是短参数,我试过,貌似还得指定至少一个短参数。
  • -l 参数指定的就是长参数。
  • 多个参数用逗号 , 分隔。
  • 参数后面跟一个冒号 : 表示这个参数(option)必须要给一个参数(argument),类似上面的 --prefix=/path/to/install 这种。
  • 参数后面跟2个冒号 :: 表示这个参数后面的参数可有可无。比如例子里面的 --initdb

find exec 提示 No such file or directory

这个是之前用来日志删除的一个程序,大概命令类似 find ./ -name '2012*' -exec rm -r {} \;,后来总发现报 No such file or directory 这个错误,可是去看的时候,发现那些目录也被删掉了。开始觉得可能是有其他人的程序也在删除这个目录,问了一圈结果没人删。

后来经过测试琢磨找到原因了,在于这个命令的执行思路大概是先去找那个名字的文件或者目录,然后挨个执行后面的命令。那么,如果找到的既有上级目录,也有下级文件的时候,如果目录先被删掉了,那删文件的时候可不就是 No such file or directory 么。

好在 find 提供了一个参数 -prune

       -prune True; if the file is a directory, do not descend into it. If -depth is given, false; no effect.  Because -delete implies -depth, you can-
              not usefully use -prune and -delete together.
comments powered by Disqus