最好的 Bash 脚本不仅能正常工作,而且编写得易于理解和修改。这得益于采用一致的变量名和编码风格。验证用户提供参数的合法性并检查命令是否成功运行也能保证脚本长时间可用。下面是一些我个人行之有效的建议。

采用一致缩进

缩进使代码更具可读性,也因此更具可维护性,尤其在代码逻辑嵌套超过三层。缩进使得脚本逻辑的基本结构非常直观。至于缩进多少空格无关紧要,尽管大部分人都倾向于使用4个或8个空格。只要确保采用缩进并进行对齐,这样就好。

#!/bin/bash

if [ $# -ge 1 ] && [ -d $1 ]; then
    for file in `ls $1`
    do
        if [ $debug == "on" ]; then
            echo working on $file
        fi
        wc -l $1/$file
    done
else
    echo "USAGE: $0 directory"
    exit 1
fi

提供有效信息

有效信息可以帮助运行脚本的人了解他们需要提供哪些参数,甚至是对两年后你自己。

if [ $# == 0 ]; then
    echo "Usage: $0 filename"
    exit 1
fi

合理使用注释

提供注释可以解释你的代码,特别是当代码比较复杂时,但不需要解释显而易见的代码行,只需要解释使用的每一条命令或者在代码段容易弄混的重要代码行。

username=$1

# make sure the account exists on the system
grep ^$username: /etc/passwd
if [ $? != 0 ]; then
    echo "No such user: $username"
    exit 1
fi

在出错退出时返回错误码

即使你不会查看错误码,但在代码出错时返回非零值是个不错的主意。有一天,也许你想找一种简单的方法来检查脚本哪里出错,那么返回值1或4或11可以帮你很快弄明白。

echo -n "In what year were you born?> "
read year

if [ $year -gt `date +%Y` ]; then
    echo "Sorry, but that's just not possible."
    exit 2
fi

使用函数替换重复命令集

函数也能让你的代码更具可读性和可维护性。如果重复使用的命令只有一条就不必麻烦,但如果很容易分离出一小撮共用命令行,就很有必要这样做。如果以后需要进行改动,只需要在一处进行即可。

function lower()
{
    local str="$@"
    local output
    output=$(tr '[A-Z]' '[a-z]'<<<"${str}")
    echo $output
}

为变量取有实际意义的名称

Unix管理员通常尽量避免输入一些额外字符,但不要在脚本中这样做。花些额外时间给变量一个有意义的命名并注意命名的一致性。

#!/bin/bash

if [ $# != 1 ]; then
    echo "Usage: $0 address"
    exit 1
else
    ip=$1
fi

检查参数类型是否正确

如果在使用参数前,对提供给脚本的输入参数进行类型检查,可以避免很多麻烦。下面是一种简单的方法,用于检查参数是否是数字。

if ! [ "$1" -eq "$1" 2> /dev/null ]
then
  echo "ERROR: $1 is not a number!"
  exit 1
fi

检查参数缺失或提供参数顺序的错误信息

不要以为使用者知道自己在做什么。如果他应该提供多个参数,请确保他提供了正确的参数。

if [ $# != 3 ]; then
    echo "What part of THREE ARGUMENTS don't you understand?"
fi

检查必要文件是否真实存在

在使用一个文件前检查它是否存在非常简单。下面的简单例子用于检查第一个输入参数指定的文件在系统上是否真实存在。

if [ ! -f $1 ]; then
    echo "$1 -- no such file"
fi

输出发送至/dev/null

将命令输出发送到 /dev/null 并以一种更加友好的方式告诉用户哪里出错,可以让你的脚本对使用者而言更加简单。

if [ $1 == "help" ]; then
    echo "Sorry -- No help available for $0"
else
    CMD=`which $1 >/dev/null 2>&1`
    if [ $? != 0 ]; then
        echo "$1: No such command -- maybe misspelled or not on your search path"
        exit 2
    else
        cmd=`basename $1`
        whatis $cmd
    fi
fi

使用错误码

你可以在脚本中使用返回码来判定一条命令的执行结果是否符合预期。

# check if the person is still logged in or has running processes
ps -U $username 2> /dev/null
if [ $? == 0 ]; then
    echo "processes:" >> /home/oldaccts/$username
    ps -U $username >> /home/oldaccts/$username
fi

信息提示

不要忘记告诉运行脚本的人他们应该知道的内容。他们不必在阅读代码后才知道你为他们创建了一个文件,特别是创建的文件不在当前文件夹中。

...
date >> /tmp/report\(
echo "Your report is /tmp/report\)"

引用所有参数扩展

如果在脚本中使用字符扩展,别忘了使用引号,这样就不会得到一个意料之外的结果。

#!/bin/bash

msg="Be careful to name your files *.txt"
# this will expand *.txt
echo $msg
# this will not
echo "$msg"

引用所有参数时使用$@

$@变量会列出所有提供给脚本的参数,并且非常容易使用,正如下面一段脚本摘录所示。

#!/bin/bash

for i in "$@"
do
    echo "$i"
done

一些额外的注意和一致性可能意味着你现在编写的脚本将在之后很多年都易于使用。

余下全文(1/3)
分享这篇文章:

请关注我们:

《Bash 优良编程实践》有1个想法

  1. test 对这篇文章的反应是赞一个

发表评论

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