|
|
4#

楼主 |
发表于 2009-4-28 12:33:40
|
只看该作者

文档,文档,文档
我们在职业生涯中早晚会受到这个问题的困扰。老板要求您看看一个 10 年前编写的脚本,它的作者已经不再为公司工作了。您会说 “没问题” 吗?通常情况下,可能没问题;但是,如果这个脚本很复杂,执行了您不习惯使用的命令,采用的编写风格与您的风格不一样,或者干脆就不能正常工作,您就遇到大麻烦了。在这种情况下,一些反映作者当初编写这个脚本时的想法的提示会有很大的帮助。有时候,您开发了一个自认为只使用一次的脚本,但是以后却发现还需要修改它。或者,您用几星期时间编写了一个巨大的脚本,您了解这个脚本的所有细节,但是如果别人阅读它,却不知所云。这几种情况说明,文档之于开发人员就像脚本之于用户,都非常重要。
看看清单 6 所示的函数。
清单 6. 没有注释的脚本示例
confirm_and_exit() {
[[ ${_DEBUG_LEVEL} -ge 3 ]] && set -x
while [[ -z ${_EXIT_ANS} ]]
do
cup_echo "Are you sure you want to exit? [Y/N]
\c" ${_PROMPT_ERR_ROW} ${_PROMPT_ERR_COL}
${_TPUT_CMD} cnorm
read ${_NO_EOL_FLAG:+${_READ_FLAG:-'-n'}} ${_NO_EOL_FLAG} _EXIT_ANS
${_TPUT_CMD} civis
done
case ${_EXIT_ANS} in
[Nn]) unset _EXIT_ANS; return 0;;
[Yy]) exit_msg 0 1 "Exiting Script";;
*) invalid_selection ${_EXIT_ANS}; unset _EXIT_ANS;;
esac
return 0
}
如果您有比较丰富的 shell 脚本编程经验,可能能够读懂这个脚本。但是,脚本编程的初学者很难理解这个函数的作用。如果花上几分钟在这个脚本中添加注释,情况就大不一样了。清单 7 给出包含注释的同一个函数。
清单 7. 包含注释的脚本示例
#########################################
# function confirm_and_exit
#########################################
confirm_and_exit() {
# if the debug level is set to 3 or higher, send every evaluated line to stdout
[[ ${_DEBUG_LEVEL} -ge 3 ]] && set –x
# Continue to prompt the user until they provide a valid answer
while [[ -z ${_EXIT_ANS} ]]
do
# prompt user if they want to exit the script
# cup_echo function calls tput cup <x> <y>
# syntax:
# cup_echo <string to display> <row on stdout to display>
<column on stdout to display>
cup_echo "Are you sure you want to exit? [Y/N]
\c" ${_PROMPT_ERR_ROW} ${_PROMPT_ERR_COL}
# change cursor to normal via tput
${_TPUT_CMD} cnorm
# read value entered by user
# if _NO_EOL_FLAG is supplied, use value of _READ_FLAG or “-n”
# if _NO_EOL_FLAG is supplied, use value as characters aloud on read
# assign value entered by user to variable _EXIT_ANS
read ${_NO_EOL_FLAG:+${_READ_FLAG:-'-n'}} ${_NO_EOL_FLAG} _EXIT_ANS
# change cursor to invisible via tput
${_TPUT_CMD} civis
done
# if user entered “n”, return to previous block of code with return code 0
# if user entered “y”, exit the script
# if user entered anything else, execute function invalid_selection
case ${_EXIT_ANS} in
[Nn]) unset _EXIT_ANS; return 0;;
[Yy]) exit_msg 0 1 "Exiting Script";;
*) invalid_selection ${_EXIT_ANS}; unset _EXIT_ANS;;
esac
# exit function with return code 0
return 0
}
对于这么小的函数,这似乎太麻烦了,甚至有点过分,但是对于 shell 脚本编程新手和阅读这个函数的人员而言,注释是非常有价值的。
在 shell 脚本中,注释的另一个极其有帮助的用途是,解释变量的有效值以及解释返回码的含义。
清单 8 中的示例取自一个 shell 脚本的开头。
清单 8. 未加注释的变量示例
#!/usr/bin/bash
trap 'exit_msg 1 0 "Signal Caught. Exiting..."' HUP INT QUIT KILL ABRT
trap 'window_size_changed' WINCH
_MSG_SLEEP_TIME=3
_RETNUM_SIZE=6
_DEBUG_LEVEL=0
_TMPDIR="/tmp"
_SP_LOG="${0##*/}.log"
_SP_REQUESTS="${HOME}/sp_requests"
_MENU_ITEMS=15
LESS="-P LINE\: %l"
export _SP_REQUESTS _TMPDIR _SP_LOG _DB_BACKUP_DIR
export _DEBUG_LEVEL _NEW_RMSYNC _RMTOTS_OFFSET_COL
同样,很难理解 trap 语句的作用以及每个变量可以是哪些值。除非把整个脚本都读一遍,否则不可能看出这些变量的意义。另外,这里没有提到这个脚本中使用的任何返回码。这会大大增加解决 shell 脚本问题的难度。向 清单 8 的代码行中添加一些注释和一个专门描述返回码的注释块,这样就可以显著降低理解难度。看看下面的清单 9。
清单 9. 带注释的变量示例
#!/usr/bin/bash
#########################################################################
# traps
#########################################################################
# trap when a user is attempting to leave the script
trap 'exit_msg 1 0 "Signal Caught. Exiting..."' HUP INT QUIT KILL ABRT
trap 'window_size_changed' WINCH # trap when a user has resized the window
#########################################################################
#########################################################################
# defined/exported variables
#########################################################################
_MSG_SLEEP_TIME=3 # seconds to sleep for all messages
# (if not defined, default will is 1 second)
_CUSTNUM_SIZE=6 # length of a customer number in this location
# (if not defined, default is 6)
_DEBUG_LEVEL=0 # log debug messages. log level is accumulative
# (i.e. 1 = 1, 2 = 1 & 2, 3 = 1, 2, & 3)
# (if not defined, default is 0)
# Log levels:
# 0 = No messages
# 1 = brief messages (start script, errors, etc)
# 2 = environment setup (set / env)
# 3 = set -x (A LOT of spam)
_TMPDIR="/tmp" # directory to put work/tmp files
# (if not defined, default is /tmp)
_SP_LOG="${0##*/}.log" # log of script events
_SP_REQUESTS="${HOME}/sp_requests"
# file to customer record requests,
# also read at startup
_MENU_ITEMS=15 # default number of items to display per page
# (it not defined, default is 10)
LESS="-P LINE\: %l" # format 'less' prompt. MAN less if more info
# export the variables defined above
export _MSG_SLEEP_TIME _CUSTNUM_SIZE _DEBUG_LEVEL _TMPDIR
_SP_LOG _SP_REQUESTS _MENU_ITEMS
#########################################################################
看起来好多了,不是吗?所有东西都组织有序,并且有详细的描述,初次阅读这个脚本的人更容易理解它的作用。 |
|