这里的技术tips原文来自Google的“TestingontheToilet”(TOTT)。这是一个修订和扩展的版本。脚本安全我所有的bash脚本都以:#!/bin/bashset-onounsetset-oerrexit这避免了两个常见问题:引用未定义的变量(默认为“”)忽略执行失败的命令。需要注意的是,某些Linux命令的某些参数可以强制忽略错误,例如“mkdir-p”和“rm-f”。另请注意,在“errexit”模式下,虽然可以有效捕获错误,但并非所有失败的命令都可以捕获。在某些情况下,无法检测到某些失败的命令。(有关详细信息,请参阅这篇文章。)脚本函数在bash中,您可以定义函数,这些函数就像任何其他命令一样,可以随意使用;它们使您的脚本更具可读性:ExtractBashComments(){egrep"^#"}catmyscript.sh|ExtractBashComments|wccomments=$(ExtractBashComments&2}log"INFO""amessage"将尽可能多的bash代码移动到函数中,只保留全局变量、常量和对“main”的调用放在最外层。变量注解Bash可以对变量进行有限的注解。两个最重要的注解是:local(函数内部变量)readonly(只读变量)#ausefulidiom:DEFAULT_VALcanbeoverwritten#withanenvironmentvariableofthesamenamereadonlyDEFAULT_VAL=${DEFAULT_VAL:-7}myfunc(){#initializealocalvariablewiththeglobaldefaultlocalsome_var=${DEFA...}这样,你就可以将一个之前不是只读变量的变量声明为只读变量:x=5x=6readonlyxx=7#failure尝试在你的bash脚本中将所有变量都注释为local或readonly。使用$()而不是反引号(`)反引号很难看,而且在某些字体中与反引号非常相似。$()可以内联使用,避免了转义字符的麻烦。#bothcommandsbelowprintout:A-B-C-Decho"A-`echoB-\`echoC-\\\`echoD\\\`\``"echo"A-$(echoB-$(echoC-$(echoD)))"与[[]](双括号)代替[]使用[[]]可以避免文件扩展名异常等问题,并且可以带来很多语法上的改进,还增加了很多新特性:运算符函数解释||logicalor(只用在双方括号中)&&logicaland(只用在双方括号中)<字符串比较(双方括号中不需要传递)-ltnumbercomparison=stringequality==inGlobbingmodeStringcomparison(only用在双方括号中,见下文)=~字符串与正则表达式比较(只用在双方括号中,见下文)-n非空字符串-z空字符串-eq数等于-ne数不等于单方括号:["${name}"\>"a"-o${name}\<"m"]双方括号[["${name}">"a"&&"${name}"<"m"]]正则表达式/通配符下面的示例充分展示了使用双括号的好处:t="abc123"[["$t"==abc*]]#true(全局比较)[["$t"=="abc*"]]#false(文字比较)[["$t"=~[abc]+[123]+]]#true(常规expressioncomparison)[["$t"=~"abc*"]]#false(literalcomparison)注意从bashversion3.2开始,正则表达式和globbing表达式都不能用引号括起来,如果你的表达式中有空格,可以存储在一个变量中:r="ab+"[["abbb"=~$r]]#trueGlobbing模式下的字符串比较也可以用在case语句中:case$tinabc*);;esac#p#Stringoperation在Bash中有多种操作字符串的方法,其中有许多是不可取的。基本用户f="path1/path2/file.ext"len="${#f}"#=20(stringlength)#slice操作:${:}or${:<开始>:<长度>}slice1="${f:6}"#="path2/file.ext"slice2="${f:6:5}"#="path2"slice3="${f:-8}"#="file.ext"(注意:"-"前有一个空格)pos=6len=5slice4="${f:${pos}:${len}}"#="path2"替换操作(使用globbing)f="path1/path2/file.ext"single_subst="${f/path?/x}"#="x/path2/file.ext"global_subst="${f//path?/x}"#="x/x/file.ext"#stringsplittingreadonlyDIR_SEP="/"array=(${f//${DIR_SEP}/})second_dir="${arrray[1]}"#=path2deletetheheadortail(usingglobbing)f="path1/path2/file.ext"#deletethestringheadextension="${f#*.}"#="ext"#匹配贪婪方式删除字符串headfilename="${f##*/}"#="file.ext"#删除字符串taildirname="${f%/*}"#="path1/path2"#用贪婪匹配法删除字符串的末尾root="${f%%/*}"#="path1》避免使用临时文件,有些命令需要通过文件名来参数化,所以不能使用管道。这时<()就派上用场了,它可以接受一个命令,并将其转换成文件名.像:#Downloadandcomparetwowebpagesdiff<(wget-O-url1)<(wget-O-url2)还有一个非常有用的“heredocuments”,它可以让你输入标准输入输入多-上面的行字符串。下面的'MARKER'可以用任何单词替换。#任意单词都可以作为分隔符命令<