第32章. 脚本编程风格
写脚本时养成结构化和系统方法的习惯. 即使你在信封背后随便做一下草稿也是有益的,要养成在写代码前花几分钟来规划和组织你的想法.
这儿是一些风格的指南. 注意这节文档不是想成为一个官方Shell编程风格.
32.1. 非官方的 Shell 脚本风格
注释你的代码.这会使你的代码更容易让别人理解和赏识,同时也便于你维护.
1 PASS="$PASS${MATRIX:$(($RANDOM%${#MATRIX})):1}" 2 # 当你去年写下这句代码时非常的了解它在干什么事,但现在它完全是一个谜. 3 # (摘自 Antek Sawicki的"pw.sh" 脚本.)
给脚本和函数加上描述性的头部信息.
1 #!/bin/bash 2 3 #************************************************# 4 # xyz.sh # 5 # written by Bozo Bozeman # 6 # July 05, 2001 # 7 # # 8 # 清除项目文件. # 9 #************************************************# 10 11 E_BADDIR=65 # 没有那样的目录. 12 projectdir=/home/bozo/projects # 要清除的目录. 13 14 # --------------------------------------------------------- # 15 # cleanup_pfiles () # 16 # 删除指定目录里的所有文件. # 17 # 参数: $target_directory # 18 # 返回: 成功返回0 , 失败返回$E_BADDIR值. # 19 # --------------------------------------------------------- # 20 cleanup_pfiles () 21 { 22 if [ ! -d "$1" ] # 测试目标目录是否存在. 23 then 24 echo "$1 is not a directory." 25 return $E_BADDIR 26 fi 27 28 rm -f "$1"/* 29 return 0 # 成功. 30 } 31 32 cleanup_pfiles $projectdir 33 34 exit 0
确认 #!/bin/bash在脚本的第一行,在任何头部注释行之前.
避免使用 "魔数,"
它是硬编码的字符常量. 用有意义的变量名来代替. 这使脚本更容易理解并允许在不破坏应用的情况下做改变和更新.
1 if [ -f /var/log/messages ] 2 then 3 ... 4 fi 5 # 一年以后,你决定让脚本改为检查 /var/log/syslog. 6 # 那么现在就需要你手动修改脚本里每一处的要改动的代码, 7 # 希望不要有你疏漏的地方. 8 9 # 更好的办法是: 10 LOGFILE=/var/log/messages # 只需要改动一行. 11 if [ -f "$LOGFILE" ] 12 then 13 ... 14 fi
为变量和函数选择描述性的名字.
1 fl=`ls -al $dirname` # 含义含糊. 2 file_listing=`ls -al $dirname` # 更好的名字. 3 4 5 MAXVAL=10 # 同一个脚本所有程序代码使用脚本常量. 6 while [ "$index" -le "$MAXVAL" ] 7 ... 8 9 10 E_NOTFOUND=75 # 把错误代码的代表的变量名大写U, 11 # +并以"E_"开头. 12 if [ ! -e "$filename" ] 13 then 14 echo "File $filename not found." 15 exit $E_NOTFOUND 16 fi 17 18 19 MAIL_DIRECTORY=/var/spool/mail/bozo # 环境变量名用大写. 20 export MAIL_DIRECTORY 21 22 23 GetAnswer () # 函数名用适当的大小写混合组成. 24 { 25 prompt=$1 26 echo -n $prompt 27 read answer 28 return $answer 29 } 30 31 GetAnswer "What is your favorite number? " 32 favorite_number=$? 33 echo $favorite_number 34 35 36 _uservariable=23 # 语法允许, 但不推荐. 37 # 用户定义的变量最好不要用下划线开头. 38 # 把这个留给系统变量使用更好.
用有含义和系统的方法来使用退出代码(exit codes).
1 E_WRONG_ARGS=65 2 ... 3 ... 4 exit $E_WRONG_ARGS
也参考附录 D.
最后建议在脚本中使用/usr/include/sysexits.h的退出码, 虽然它们主要由 C 和 C++语言编程时使用.
使用标准的参数选项.最后建议使用下面一组参数标志.
1 -a All: Return all information (including hidden file info). 2 -b Brief: Short version, usually for other scripts. 3 -c Copy, concatenate, etc. 4 -d Daily: Use information from the whole day, and not merely 5 information for a specific instance/user. 6 -e Extended/Elaborate: (often does not include hidden file info). 7 -h Help: Verbose usage w/descs, aux info, discussion, help. 8 See also -V. 9 -l Log output of script. 10 -m Manual: Launch man-page for base command. 11 -n Numbers: Numerical data only. 12 -r Recursive: All files in a directory (and/or all sub-dirs). 13 -s Setup & File Maintenance: Config files for this script. 14 -u Usage: List of invocation flags for the script. 15 -v Verbose: Human readable output, more or less formatted. 16 -V Version / License / Copy(right|left) / Contribs (email too).
也参考附录 F.
把复杂的脚本分割成简单一些的模块. 用合适的函数来实现各个功能. 参考例子 34-4.
如果有简单的结构可以使用,不要使用复杂的结构.
1 COMMAND 2 if [ $? -eq 0 ] 3 ... 4 # 多余的并且也不直接明了. 5 6 if COMMAND 7 ... 8 # 更简练 (或者可能会损失一些可读性).
... reading the UNIX source code to the Bourne shell (/bin/sh). Iwas shocked at how much simple algorithms could be made cryptic, andtherefore useless, by a poor choice of code style. I asked myself,"Could someone be proud of this code?"
Landon Noll
注
在上下文, "魔数"和用来指明文件类型的 魔数(magic numbers)有完全不同的意思.