34. 陷阱

# 第34章 陷阱

Turandot: Gli enigmi sono tre, la morte una! Caleph: No, no! Gli enigmi sono tre, una la vita!

——Puccini

以下的做法(非推荐)将让你原本平淡无奇的生活激动不已。

  • 将保留字或特殊字符声明为变量名。

case=value0       # 引发错误。
23skidoo=value1   # 也会引发错误。
# 以数字开头的变量名是被shell保留使用的。
# 试试_23skidoo=value1。以下划线开头的变量名就没问题.

# 然而 . . .   只用一个下划线作为变量名就不行。
_=25
echo $_           # $_是一个特殊变量, 代表最后一个命令的最后一个参数。
# 但是,_是一个有效的函数名!

xyz((!*=value2    # 引起严重的错误。
# Bash3.0之后,标点不能出现在变量名中。
  • 使用连字符或其他保留字符来做变量名(或函数名)。

  • 让变量名与函数名相同。 这会使得脚本的可读性变得很差。

  • 不合时宜的使用空白符。与其他编程语言相比,Bash非常讲究空白符的使用。

  • 假定未被初始化的变量(赋值前的变量)被“清0”。事实上,未初始化的变量值为“null”,而不是0。

  • 混淆测试符号=和-ep。请记住,=用于比较字符变量,而-ep用来比较整数。

样例 34-1. 数字比较与字符串比较并不相同

  • 试图用let来设置字符串变量。

  • 有时候在“test”中括号([ ])结构里的变量需要被引用起来(双引号)。如果不这么做的话,可能会引起不可预料的结果。请参考例子 7-6例子 16-5例子 9-6

  • 为防分隔,用双引号引用一个包含空白符的变量。 有些情况下,这会产生意想不到的后果

  • 脚本中的命令可能会因为脚本宿主不具备相应的运行权限而导致运行失败。如果用户在命令行中不能调用这个命令的话,那么即使把它放到脚本中来运行,也还是会失败。这时可以通过修改命令的属性来解决这个问题,有时候甚至要给它设置suid位(当然, 要以root身份来设置)。

  • 试图使用-作为作为重定向操作符(事实上它不是),通常都会导致令人不快的结果。

  • 使用Bash 2.0或更高版本的功能,可以在产生错误信息的时候,引发修复动作。但是比较老的Linux机器默认安装的可能是Bash 1.XX。

  • 一个带有DOS风格换行符(\r\n)的脚本将会运行失败,因为#!/bin/bash\r\n是不合法的,与我们所期望的#!/bin/bash\n不同,解决办法就是将这个脚本转换为UNIX风格的换行符。

  • #!/bin/sh开头的Bash脚本,不能在完整的Bash兼容模式下运行。某些Bash特定的功能可能会被禁用。如果脚本需要完整的访问所有Bash专有扩展,那么它需要使用#!/bin/bash作为开头。

  • 如果在here document中,结尾的limit string之前加上空白字符的话,将会导致脚本的异常行为。

  • 在一个输出被捕获的函数中放置了不止一个echo语句。

这是行不通的。

  • 脚本不能将变量export到它的父进程(即调用这个脚本的shell),或父进程的环境中。就好比我们在生物学中所学到的那样,子进程只会继承父进程, 反过来则不行。

  • 可以确定的是,即使回到命令行提示符,变量$WHATEVER仍然没有被设置。

  • 子shell中设置和操作变量之后,如果尝试在子shell作用域之外使用同名变量的话, 将会产生令人不快的结果。

样例 34-2. 子shell缺陷

  • 将echo的输出通过管道传递给read命令可能会产生不可预料的结果。在这种情况下,read命令的行为就好像它在子shell中运行一样。可以使用set命令来代替(就好像例子15-18一样)。

样例 34-3. 将echo的输出通过管道传递给read命令

事实上,也正如Anthony Richardson指出的那样,通过管道将输出传递到任何循环中, 都会引起类似的问题。

  • 一个相关的问题:当你尝试将tail -f的stdout通过管道传递给grep时,会产生问题。

  • 在脚本中使用“suid”命令是非常危险的,因为这会危及系统安全。

  • 使用shell脚本来编写CGI程序是值得商榷的。因为Shell脚本的变量不是“类型安全”的,当CGI被关联的时候,可能会产生令人不快的行为。此外,它还很难抵挡住“破解的考验”。

  • Bash不能正确地处理双斜线(//)字符串

  • 在Linux或BSD上编写的Bash脚本,可能需要修改一下,才能使它们运行在商业的UNIX机器上。这些脚本通常都使用GNU命令和过滤工具,GNU工具通常都比一般的UNIX上的同类工具更加强大。这方面的一个非常明显的例子就是,文本处理工具tr

  • 遗憾的是,更新Bash本身就会破坏过去工作完全正常的脚本。让我们回顾一下使用无正式文件的Bash功能有多危险

危险正在接近你 -- 小心,小心,小心,小心。 许多勇敢的心都在沉睡。 所以一定要小心 -- 小心。

——A.J. Lamb and H.W. Petrie

注意事项

Last updated

Was this helpful?