- 原文地址:https://google.github.io/styleguide/shell.xml
- 注:代码片段内的注释未翻译,怕影响美观。
背景
使用哪种Shell
Bash
是唯一被允许用于编写可执行文件的Shell脚本语言(译注:存在多种Shell语言,可参考Wikipedia:Unix_Shell。可执行文件必须以
#!/bin/bash
开始(译注:Wikipedia:Shebang),并且使用最小数量的执行选项(译注:Find out what your UNIX shell's flags are & then change them , The Set Builtin)。使用
set
设置shell执行选项,以便用bash <腳本名>
的方式调用脚本时候不会破坏执行选项的功能。限制所有的可执行shell脚本统一使用bash使得我们在机器上能统一安装一种shell 。唯一的例外,你正在编写的项目强制你使用其他shell语言。例如Solaris SVR4软件包要求包内的任何脚本用纯Bourne shell编写(译注:即sh,参考Wikipedia:Bourne_shell)。
什么时候使用Shell
Shell应该只用于编写小工具或者简单的包装脚本(译注:wrapper scripts,Shell Wrappers)。
尽管shell脚本不是一种开发语言,但在Google内部它被用于编写各种各样的工具性脚本。在广泛的开发部署中,遵循这份编程风格指南是一种共识,而不是一个建议。
尽管shell脚本不是一种开发语言,但在Google内部它被用于编写各种各样的工具性脚本。在广泛的开发部署中,遵循这份编程风格指南是一种共识,而不是一个建议。
一些准则:
- 如果你主要是调用其他工具和做相对少量的数据处理,使用shell 来完成任务是合适的选择。
- 如果你在意性能,请使用其他工具来代替shell。
- 任何情况下,如果你发现需要使用数组(译注:Bash:Array variables),并且不是使用
${PIPESTATUS}
(译注:PIPESTATUS保存着管道中各命令的返回值),你应该使用Python。 - 如果你要编写一份超过一百行的Shell 脚本,你应该尽量使用Python 来编写。记住,随着Shell脚本行数的增长,尽早使用其他语言来重写你的脚本,以免将来重写的时候浪费更多的时间。
Shell文件和解释器调用
文件扩展名
可执行文件应该不带扩展名(强烈建议)或者使用
当我们执行一个程序的时候不需要知道它是用什么语言写的,并且shell也不要求脚本必须带扩展名。所以我们不希望一个可执行文件带着扩展名。
然而,对于库文件来说知道是什么语言写的却非常重要,有时需要使用不同的语言编写类似的库文件。使用代表语言的文件名后缀(即扩展名),就可以让使用不同语言编写的具有同样功能的库件有着相同的名字。
.sh
的扩展名。库文件应该带一个.sh
的扩展名,并且不应该是可执行的。当我们执行一个程序的时候不需要知道它是用什么语言写的,并且shell也不要求脚本必须带扩展名。所以我们不希望一个可执行文件带着扩展名。
然而,对于库文件来说知道是什么语言写的却非常重要,有时需要使用不同的语言编写类似的库文件。使用代表语言的文件名后缀(即扩展名),就可以让使用不同语言编写的具有同样功能的库件有着相同的名字。
SUID/SGID
禁止在Shell脚本中使用SUID或SGID (译注:What is SUID, SGID and Sticky bit ?)
shell存在太多的安全问题,以至于允许SUID/SGID后几乎不可能保证shell的安全。虽然bash让运行SUID变得困难,但是在某些平台上还是有可能,所以我们明确禁止使用它。
当你需要提权的时候,使用
shell存在太多的安全问题,以至于允许SUID/SGID后几乎不可能保证shell的安全。虽然bash让运行SUID变得困难,但是在某些平台上还是有可能,所以我们明确禁止使用它。
当你需要提权的时候,使用
sudo
(译注:Wikipedia:sudo)。环境
STDOUT vs STDERR
所有的錯誤信息應該傳入STDERR(譯註:標準錯誤輸出,延伸閱讀:I/O Redirection) 這使得從實際問題中區分正常狀態變得容易。
推薦使用一個函數來專門打印錯誤信息和其他狀態信息。
推薦使用一個函數來專門打印錯誤信息和其他狀態信息。
err() {
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $@" >&2
}
if ! do_something; then
err "Unable to do_something"
exit "${E_DID_NOTHING}"
fi
註釋
文件頭
每個文件的開頭必須有一段關於它內容的概述
每個文件必須在開頭部分包含一段關於其內容的概述的註釋。也可以選擇添加版權聲明和作者信息。
例:
每個文件必須在開頭部分包含一段關於其內容的概述的註釋。也可以選擇添加版權聲明和作者信息。
例:
1 2 3 | #!/bin/bash
#
# Perform hot backups of Oracle databases.
|
函數註釋
除了簡短、明確的函數之外,任何一個函數都必須寫註釋。庫文件的中的任何一個函數必須寫註釋,無論其長短和複雜性。
他人應該能夠在不閱讀源碼的情況下通過閱讀註釋(和幫助信息,如果有提供的話),從而學會使用你的程序或者庫文件中的函數。
所有函數的註釋都應該包含:
他人應該能夠在不閱讀源碼的情況下通過閱讀註釋(和幫助信息,如果有提供的話),從而學會使用你的程序或者庫文件中的函數。
所有函數的註釋都應該包含:
- 對函數的描述;
- 會使用或修改的全局變量;
- 函數傳參;
- 返回值,不是運行的最後一條命令默認的退出狀態碼。
例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #!/bin/bash
#
# Perform hot backups of Oracle databases.
export PATH='/usr/xpg4/bin:/usr/bin:/opt/csw/bin:/opt/goog/bin'
#######################################
# Cleanup files from the backup dir
# Globals:
# BACKUP_DIR
# ORACLE_SID
# Arguments:
# None
# Returns:
# None
#######################################
cleanup() {
...
}
|
實現的註釋
代码中使用了技巧,或晦涩难懂,或有趣,或十分重要的部分你都应该添加注释。
这里要遵循Google代码注释的通用惯例。不要任何东西都添加注释。如果是一个复杂的算法,或者你在做一些与众不同的事情,加一段简短的注释。
这里要遵循Google代码注释的通用惯例。不要任何东西都添加注释。如果是一个复杂的算法,或者你在做一些与众不同的事情,加一段简短的注释。
TODO 注释
对临时性的代码,或短期的解决方案,或足够好但是不够完美的代码等添加TODO注释。
这和C++ Guide中的做法约定一致。
TODO注释都应该在开头包含大写的TODO,跟着是一对小括号,中间注明你的用户名。冒号是可选的。最好也在TODO条目末尾添加bug/ticket号码。
例:
这和C++ Guide中的做法约定一致。
TODO注释都应该在开头包含大写的TODO,跟着是一对小括号,中间注明你的用户名。冒号是可选的。最好也在TODO条目末尾添加bug/ticket号码。
例:
# TODO(mrmonkey): Handle the unlikely edge cases (bug ####)
格式
修改代码的时候应该遵循现存代码风格,任何新代码都应该遵循下列规范。
缩进
使用两个空格做缩进,不要使用tabs。
在代码块之间使用空行提提高可读性。缩进是两个空格。无论如何都不要使用tabs。对于已经存在的文件,如实的保留已经存在的缩进。
在代码块之间使用空行提提高可读性。缩进是两个空格。无论如何都不要使用tabs。对于已经存在的文件,如实的保留已经存在的缩进。
行宽和长字符串
行宽最大为80个字符。
如果不得不写超过80个字符的字符串,你应该尽可能的使用here文档(译注:Wikipedia:Here文档)或者嵌入新行。如果有超过80个字符的字符串并且不能被分割,这是可以的,但是强烈建议找到一个合适的方法让它变短。
如果不得不写超过80个字符的字符串,你应该尽可能的使用here文档(译注:Wikipedia:Here文档)或者嵌入新行。如果有超过80个字符的字符串并且不能被分割,这是可以的,但是强烈建议找到一个合适的方法让它变短。
# DO use 'here document's
cat <<END;
I am an exceptionally long
string.
END
# Embedded newlines are ok too
long_string="I am an exceptionally
long string."
管道
如果一行写不下整条管道,那么应该一行一个管段的进行分割。
如果一行能写下一条管道,那么就应该写到一行。
如果写不下,就应该将管道分割为一个管段一行,以2个空格作为缩进。这个规范适用与使用“|”链接起来的组合命令以及使用“||”和“&&”的组合逻辑语句。
如果一行能写下一条管道,那么就应该写到一行。
如果写不下,就应该将管道分割为一个管段一行,以2个空格作为缩进。这个规范适用与使用“|”链接起来的组合命令以及使用“||”和“&&”的组合逻辑语句。
# All fits on one line
command1 | command2
# Long commands
command1 \
| command2 \
| command3 \
| command4
循环
; do
, ; then
与while
, for
或if
应置于同一行。Shell中的循环有一点特别,但是我们遵循和声明函数时大括号的相同的准则。即
; then
和; do
应该和if/for/while语句写在同一行。else
应该独占一行,结束声明也应该独占一行,并且和开始声明垂直对齐。
例:
for dir in ${ dirs_to_cleanup } ; do
if [[ -d " ${ dir } / ${ ORACLE_SID } " ]]; then
log_date "Cleaning up old files in ${dir}/${ORACLE_SID}"
rm "${dir}/${ORACLE_SID}/"*
if [[ "$?" -ne 0 ]]; then
error_message
fi
else
mkdir -p "${dir}/${ORACLE_SID}"
if [[ "$?" -ne 0 ]]; then
error_message
fi
fi
done
Case 聲明
- 可以選擇2個空格作爲縮進。
- 匹配行右括號後面和
;;
前面都需要加一個空格。 - 匹配模式,操作和
;;
應該分成不同的行。長的語句或者多命令組合語句應該切割成多行。
匹配表達式應該比
case
和esac
縮進一級。多行操作應該再縮進一級。一般情況下,不需要給匹配表達式加引號。匹配模式前面不應該有左括號。避免使用;&
和;;&
這些標記。case "${expression}" in
a)
variable="..."
some_command "${variable}" "${other_expr}" ...
;;
absolute)
actions="relative"
another_command "${actions}" "${other_expr}" ...
;;
*)
error "Unexpected expression '${expression}'"
;;
esac
變量
按優先級排序:和已存的風格一致;給你的變量加引號;推薦使用"${var}"而不是"$var",但是視具體而定。
這些僅僅是指南,因爲這個主題內容作爲強制規定似乎是有爭議的。
以下按照優先級排列:
這些僅僅是指南,因爲這個主題內容作爲強制規定似乎是有爭議的。
以下按照優先級排列:
- 和現存代碼的風格保持一致。
- 給變量加引號,參考「加引號」一節。
- 如果不是絕對必要或爲了避免歧義,不要用大括號把單個字符的shell 變量或 特殊參數(譯註:指$?,$$,$@,$*等這類參數,Special Parameters)或位置參數(譯註:Positional Parameters)。推薦將其他所有變量都用大括號括起來。
# Section of recommended cases.
# Preferred style for 'special' variables:
echo "Positional: $1" "$5" "$3"
echo "Specials: !=$!, -=$-, _=$_. ?=$?, #=$# *=$* @=$@ \$=$$ ..."
# Braces necessary:
echo "many parameters: ${10}"
# Braces avoiding confusion:
# Output is "a0b0c0"
set -- a b c
echo "${1}0${2}0${3}0"
# Preferred style for other variables:
echo "PATH=${PATH}, PWD=${PWD}, mine=${some_var}"
while read f; do
echo "file=${f}"
done < <(ls -l /tmp)
# Section of discouraged cases
# Unquoted vars, unbraced vars, brace-quoted single letter
# shell specials.
echo a=$avar "b=$bvar" "PID=${$}" "${1}"
# Confusing use: this is expanded as "${1}0${2}0${3}0",
# not "${10}${20}${30}
set -- a b c
echo "$10$20$30"
加引號
- 包含變量的字符串,命令替換,空格和shell 元字符都必須加引號,除了一定要仔細得處理表達式,不加引號。
- 推薦給包含單詞的字符串加引號(不包括命令選項或路徑名)
- 不要給字面上的整數加引號。
- 仔細處理
[[
中匹配模式的引號。 - 堅持使用"$@",除非你有原因要使用 $* 。
# 'Single' quotes indicate that no substitution is desired.
# "Double" quotes indicate that substitution is required/tolerated.
# Simple examples
# "quote command substitutions"
flag="$(some_command and its args "$@" 'quoted separately')"
# "quote variables"
echo "${flag}"
# "never quote literal integers"
value=32
# "quote command substitutions", even when you expect integers
number="$(generate_number)"
# "prefer quoting words", not compulsory
readonly USE_INTEGER='true'
# "quote shell meta characters"
echo 'Hello stranger, and well met. Earn lots of $$$'
echo "Process $$: Done making \$\$\$."
# "command options or path names"
# ($1 is assumed to contain a value here)
grep -li Hugo /dev/null "$1"
# Less simple examples
# "quote variables, unless proven false": ccs might be empty
git send-email --to "${reviewers}" ${ccs:+"--cc" "${ccs}"}
# Positional parameter precautions: $1 might be unset
# Single quotes leave regex as-is.
grep -cP '([Ss]pecial|\|?characters*)$' ${1:+"$1"}
# For passing on arguments,
# "$@" is right almost everytime, and
# $* is wrong almost everytime:
#
# * $* and $@ will split on spaces, clobbering up arguments
# that contain spaces and dropping empty strings;
# * "$@" will retain arguments as-is, so no args
# provided will result in no args being passed on;
# This is in most cases what you want to use for passing
# on arguments.
# * "$*" expands to one argument, with all args joined
# by (usually) spaces,
# so no args provided will result in one empty string
# being passed on.
# (Consult 'man bash' for the nit-grits ;-)
set -- 1 "2 two" "3 three tres"; echo $# ; set -- "$*"; echo "$#, $@")
set -- 1 "2 two" "3 three tres"; echo $# ; set -- "$@"; echo "$#, $@")
特性和坑
命令替換
使用
嵌套的反引號需要在內部使用
例:
$(command)
代替反引號。嵌套的反引號需要在內部使用
\
轉義。嵌套的$(command)
不需要改變格式,可讀性也更好。例:
# This is preferred:
var="$(command "$(command1)")"
# This is not:
var="`command \`command1\``"
Test, [ 和 [[
推薦使用
[[ ... ]]
代替 [
,test
和/usr/bin/[
[[ ... ]]
可以降低錯誤,因爲在 [[
和]]
直接不會發生路徑擴展或單詞分割,並且[[ ... ]]
允許正則表達式而[ ... ]
不允許。# This ensures the string on the left is made up of characters in the
# alnum character class followed by the string name.
# Note that the RHS should not be quoted here.
# For the gory details, see
# E14 at http://tiswww.case.edu/php/chet/bash/FAQ
if [[ "filename" =~ ^[[:alnum:]]+name ]]; then
echo "Match"
fi
# This matches the exact pattern "f*" (Does not match in this case)
if [[ "filename" == "f*" ]]; then
echo "Match"
fi
# This gives a "too many arguments" error as f * is expanded to the
# contents of the current directory
if [ "filename" == f * ] ; then
echo "Match"
fi
检测字符串
如果可能的话,使用引号而不是过滤字符串。
检测字符串时候,Bash能够智能的处理空字符串。所以,为了让代码可读性更好,应用空或非空字符串测试,而不是过滤字符串。
检测字符串时候,Bash能够智能的处理空字符串。所以,为了让代码可读性更好,应用空或非空字符串测试,而不是过滤字符串。
# Do this:
if [[ " ${ my_var } " = "some_string" ]]; then
do_something
fi
# -z (string length is zero) and -n (string length is not zero) are
# preferred over testing for an empty string
if [[ -z " ${ my_var } " ]]; then
do_something
fi
# This is OK (ensure quotes on the empty side), but not preferred:
if [[ " ${ my_var } " = "" ]]; then
do_something
fi
# Not this:
if [[ " ${ my_var } X" = "some_stringX" ]]; then
do_something
fi
为避免对你检测的目的感到困惑,请直接使用
-z
或-n
。# Use this
if [[ -n " ${ my_var } " ]]; then
do_something
fi
# Instead of this as errors can occur if ${ my_var } expands to a test
# flag
if [[ " ${ my_var } " ]]; then
do_something
fi
文件名的通配符擴展
當對文件名使用通配符的時候,請使用準確的路徑。
因爲文件名可以以
因爲文件名可以以
-
爲開頭,所以使用./*
代替*
會更安全。# Here's the contents of the directory:
# -f -r somedir somefile
# This deletes almost everything in the directory by force
psa@bilby$ rm -v *
removed directory: `somedir'
removed `somefile'
# As opposed to:
psa@bilby$ rm -v ./*
removed `./-f'
removed `./-r'
rm: cannot remove `./somedir': Is a directory
removed `./somefile'
Eval
應該避免使用
當用於給變量賦值時,eval 可以解析輸入,設置變量,但是不能檢查這些變量是什麼。
eval
當用於給變量賦值時,eval 可以解析輸入,設置變量,但是不能檢查這些變量是什麼。
# What does this set?
# Did it succeed? In part or whole?
eval $(set_my_variables)
# What happens if one of the returned values has a space in it?
variable="$(eval some_function)"
管道導入While
相比管道導入while,更推薦使用程序替換(譯註:Process Substitution)或 for 循環。在 一個while 循環中修改的變量是不能傳遞給父進程的,因爲循環命令是允許在一個子shell 中。
管道導入while 循環中隱藏的子shell 讓追蹤bug 變得困難。
管道導入while 循環中隱藏的子shell 讓追蹤bug 變得困難。
last_line='NULL'
your_command | while read line; do
last_line="${line}"
done
# This will output 'NULL'
echo "${last_line}"
如果你確定輸入不包含空格或者特殊字符串(通常,這意味着不是用戶輸入的內容),請使用 for 循環。
total=0
# Only do this if there are no spaces in return values.
for value in $(command); do
total+="${value}"
done
使用進程替換可以重定向輸出,但是請將命令放置在一個顯式的子shell 中,而不是爲while 循環創建的隱式子shell。
total=0
last_file=
while read count filename; do
total+="${count}"
last_file="${filename}"
done < <(your_command | uniq -c)
# This will output the second field of the last line of output from
# the command.
echo "Total = ${total}"
echo "Last one = ${last_file}"
當不需要傳遞非常的結果給父shell 的時候可以使用while 循環,通常情況下更多的結果需要複雜的“解析”。另外注意一些簡單的例子通過類似aws 這樣的工具解決起來更容易。這個特性在你特別不希望改變父進程域的變量的時候也是有用的。
# Trivial implementation of awk expression:
# awk '$3 == "nfs" { print $2 " maps to " $1 }' /proc/mounts
cat /proc/mounts | while read src dest type opts rest; do
if [[ ${type} == "nfs" ]]; then
echo "NFS ${dest} maps to ${src}"
fi
done
命名習慣
函數名
使用小寫字母,用下劃線分隔單詞。使用
如果你在寫一個簡單的函數,請用小寫字母和下劃線分隔單詞。如果你在寫一個包,包名請用
::
分隔庫文件。函數名後面必須有小括號。關鍵詞function
是可選的,但在項目中應該保持一致。如果你在寫一個簡單的函數,請用小寫字母和下劃線分隔單詞。如果你在寫一個包,包名請用
::
分隔。左大括號必須和函數名在同一行(和Google 內的其他語言規範一樣),並且在函數名和小括號直接不能有空格。# Single function
my_func() {
...
}
# Part of a package
mypackage::my_func() {
...
}
當函數名後面帶"()" 的時候,關鍵詞
function
是多餘的,但是它提高了函數的辨識度。變量名
和函數名規範一致。
循環內的變量名應該和其他變量名一樣命名。
循環內的變量名應該和其他變量名一樣命名。
for zone in ${zones}; do
something_with "${zone}"
done
常量名和環境變量名
全部都應該大寫,用下劃線分隔,在文件頂部聲明。
常量和任何導出到環境的元素都應該大寫。
常量和任何導出到環境的元素都應該大寫。
# Constant
readonly PATH_TO_FILES='/some/path'
# Both constant and environment
declare -xr ORACLE_SID='PROD'
有些元素在初始設置時就成了常量(例如通過getopts,(譯註:Small getopts tutorial))。所以可以在getops 中或在某種情況中設置變量,但是應該在設置之後馬上將其設置成只讀。注意在函數內部
declare
不會對全局變量進行操作,所以推薦使用readonly
或export
來代替。VERBOSE='false'
while getopts 'v' flag; do
case "${flag}" in
v) VERBOSE='true' ;;
esac
done
readonly VERBOSE
源文件名
全小寫,如果有必要的話應該用下劃線分隔單詞。
這和Google 內部的其他代碼風格一致:
這和Google 內部的其他代碼風格一致:
maketemplate
或make_template
是可以的,但不可以是make-template
。只讀變量
使用
因爲全局變量在shell 中被廣泛使用,所以在使用它們的時候捕獲錯誤是非常重要的。當你聲明變量的時如果打算讓它們只讀,那就明確的設置一下。
readonly
或declare -r
來確保它們是只讀的。因爲全局變量在shell 中被廣泛使用,所以在使用它們的時候捕獲錯誤是非常重要的。當你聲明變量的時如果打算讓它們只讀,那就明確的設置一下。
zip_version="$(dpkg --status zip | grep Version: | cut -d ' ' -f 2)"
if [[ -z "${zip_version}" ]]; then
error_message
else
readonly zip_version
fi
使用局部變量
使用
通過使用
local
聲明函數內的變量。聲明和賦值應該在不同行。 通過使用
local
聲明局部變量來確保它們只作用於函數和子函數內部。這樣做避免污染全局命名空間,和避免不經意之間設置了一個對於函數外部十分重要的變量。my_func2() {
local name="$1"
# Separate lines for declaration and assignment:
local my_var
my_var="$(my_func)" || return
# DO NOT do this: $? contains the exit code of 'local', not my_func
local my_var="$(my_func)"
[[ $? -eq 0 ]] || return
...
}
函數位置
將所有函數一起放在常量下方。不要在函數之間挾藏可執行代碼。
如果存在函數,請將它們一起放在文件的開頭。只有includes,
不要在函數之間挾藏可執行代碼。如果這樣做會導致在debug 的時候,代碼難以跟蹤和出現意想不到的執行結果。
set
聲明和常量設置有可能出現在函數上面。不要在函數之間挾藏可執行代碼。如果這樣做會導致在debug 的時候,代碼難以跟蹤和出現意想不到的執行結果。
main
至少包含一個函數的腳本,如果足夠長的話,都應該有一個叫
爲了方便找到程序開始執行的地方,應該在所有函數的底部放一個叫
main
的函數。爲了方便找到程序開始執行的地方,應該在所有函數的底部放一個叫
main
的主函數,包含主要的程序調用。這使得其他的代碼保持一致性,也允許你使用local
定義更多的變量(如果主代碼不是一個函數是做不到的)。文件最後一行非註釋的內容應該是調用main
:main "$@"
當然,對於順序執行的簡短代碼,加'main' 函數是適得其反的,並不需要。
調用命令
檢查返回值
總是檢查返回值,並給出具體解釋信息。
對於非管道的命令,可以簡單的使用
例:
對於非管道的命令,可以簡單的使用
$?
或使用if
語句直接檢查返回值。例:
if ! mv "${file_list}" "${dest_dir}/" ; then
echo "Unable to move ${file_list} to ${dest_dir}" >&2
exit "${E_BAD_MOVE}"
fi
# Or
mv "${file_list}" "${dest_dir}/"
if [[ "$?" -ne 0 ]]; then
echo "Unable to move ${file_list} to ${dest_dir}" >&2
exit "${E_BAD_MOVE}"
fi
Bash 也有一個
PIPESTATUS
的變量,可以通過它檢查管道中各部分的返回值。如果你僅僅需要檢查整條管道的執行成功或失敗,可以參考下列做法:tar -cf - ./* | ( cd "${dir}" && tar -xf - )
if [[ "${PIPESTATUS[0]}" -ne 0 || "${PIPESTATUS[1]}" -ne 0 ]]; then
echo "Unable to tar files to ${dir}" >&2
fi
然而,當你執行其他命令後
PIPESTATUS
就會被覆蓋,如果你需要根據管道中不同部分發生的錯誤執行不同的動作,你需要在執行完命令之後立即將PIPESTATUS
賦值給一個變量(不要忘記 [
也是一個命令,抹除PIPESTATUS
的內容)。tar -cf - ./* | ( cd "${DIR}" && tar -xf - )
return_codes=(${PIPESTATUS[*]})
if [[ " ${ return_codes [ 0 ] } " -ne 0 ]]; then
do_something
fi
if [[ " ${ return_codes [ 1 ] } " -ne 0 ]]; then
do_something_else
fi
内建命令vs 外部命令
在选择调用内建命令还是外部程序时,选择内建命令。
我们推荐使用bash(1)中「Parameter Expansion」部分提到的内建命令,因为内建命令更加可靠和可移植(特别是和sed之类的命令相比)。
例:
我们推荐使用bash(1)中「Parameter Expansion」部分提到的内建命令,因为内建命令更加可靠和可移植(特别是和sed之类的命令相比)。
例:
# Prefer this:
addition=$(( ${ X } + ${ Y } ))
substitution=" ${ string / #foo/bar } "
# Instead of this:
addition="$(expr ${ X } + ${ Y } )"
substitution="$(echo " ${ string } " | sed -e 's/^foo/bar/')"
总结
始终遵循常识。
临别赠言始终遵循常识。当你编码时,花几分钟阅读一下其他代码,并熟悉它的风格。如果他们在if 条件从句中使用空格,那么你也应该这样做。如果他们的注释由星号组成的盒子围着,那么你也应该这样做。编程风格指南是为了提供一个通用的编程规范,以便人们可以集中精力在编码实现上,而不是考虑代码形式上。我们展示了整体上的风格规范,另外局部的风格也同样重要。如果你在一个文件中添加的代码的风格和原来的风格差异巨大,当阅读这份代码时,整体的韵味就被破坏了。请尽量避免这样做。好了,关于编程风格指南写的够多了,代码本身更加有趣。尽情享受吧!
No comments:
Post a Comment