Skip to content
SRE运维进阶之路SRE运维进阶之路
github icon
    • 第一部分 初见shell

      • 第一章 为什么使用shell编程
        • 第二章 和Sha-Bang(#!)一起出发

          • 2.1 调用一个脚本
            • 2.2 牛刀小试
          • 第二部分 shell基础

            • 第三章 特殊字符
              • 第四章 变量与参数

                • 4.1 变量替换
                  • 4.2 变量赋值
                    • 4.3 Bash变量是弱类型的
                      • /code/shell/part2/04_4_special_variable_types
                      • 第五章 引用

                        • 5.1 引用变量
                          • 5.2 转义
                          • 第六章 退出与退出状态
                            • 第七章 测试

                              • 7.1 测试结构
                                • 7.2 文件测试操作
                                  • 7.3 其他比较操作
                                    • 7.4 嵌套 if/then 条件测试
                                      • 7.5 牛刀小试
                                      • 第八章 运算符相关话题

                                        • 8.1 运算符
                                          • 8.2 数字常量
                                            • 8.3 双圆括号结构
                                              • 8.4 运算符优先级
                                            • 第三部分 shell进阶

                                              • 第九章 换个角度看变量

                                                • 9.1 内部变量
                                                  • 9.2 变量类型标注:declare 与 typeset
                                                    • 9.2.1 declare 的另类用法
                                                      • 9.3 $RANDOM:生成随机数
                                                      • 第十章 变量处理

                                                        • 10.1 字符串处理
                                                          • 10.1.1 使用 awk 处理字符串
                                                            • 10.1.2 参考资料
                                                              • 10.2 参数替换
                                                              • 第十一章 循环与分支

                                                                • 11.1 循环
                                                                  • 11.2 嵌套循环
                                                                    • 11.3 循环控制
                                                                      • 11.4 测试与分支
                                                                      • 第十二章 命令替换
                                                                        • 第十三章 算术扩展
                                                                        • 第四部分 命令
                                                                          • 第五部分 高级话题

                                                                            • 18 正则表达式

                                                                              • 18.1 正则表达式简介
                                                                                • 18.2文件名替换
                                                                                  • 18.3 正则表达式对照表
                                                                                  • 19 嵌入文档
                                                                                    • 20 I/O 重定向

                                                                                      • 20.1 使用 exec
                                                                                        • 20.2 重定向代码块
                                                                                          • 20.3 应用程序
                                                                                          • 第二十一章 子shell
                                                                                            • 第二十二章. 限制模式的Shell
                                                                                              • 第二十三章. 进程替换
                                                                                                • 24 函数

                                                                                                  • 24.1 复杂函数和函数复杂性
                                                                                                    • 24.2 局部变量
                                                                                                      • 24.3 不使用局部变量的递归
                                                                                                      • 25. 别名
                                                                                                        • 26. 列表结构
                                                                                                          • 27 数组
                                                                                                            • 30 网络编程
                                                                                                              • 33 选项
                                                                                                                • 第34章 陷阱
                                                                                                                  • 以下的做法(非推荐)将让你原本平淡无奇的生活激动不已。
                                                                                                                  • 第36章 杂项
                                                                                                                    • echo命令
                                                                                                                    • 第六部分 Google Shell 风格指南
                                                                                                                    • 前端学习笔记

                                                                                                                      第34章 陷阱

                                                                                                                      author iconLinuxStorycalendar icon2021年5月11日category icon
                                                                                                                      • Linux
                                                                                                                      tag icon
                                                                                                                      • Bash
                                                                                                                      timer icon大约 12 分钟

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

                                                                                                                      # 第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之后,标点不能出现在变量名中。
                                                                                                                      
                                                                                                                      1
                                                                                                                      2
                                                                                                                      3
                                                                                                                      4
                                                                                                                      5
                                                                                                                      6
                                                                                                                      7
                                                                                                                      8
                                                                                                                      9
                                                                                                                      10
                                                                                                                      11
                                                                                                                      12
                                                                                                                      • 使用连字符或其他保留字符来做变量名(或函数名)。
                                                                                                                      var-1=23
                                                                                                                      # 用 'var_1 代替。
                                                                                                                      
                                                                                                                      function-whatever ()   # 错误
                                                                                                                      # 用 ‘function_whatever ()’ 代替。
                                                                                                                      
                                                                                                                       
                                                                                                                      # Bash3.0之后,标点不能出现在函数名中。
                                                                                                                      function.whatever ()   # 错误
                                                                                                                      # 用 ‘functionWhatever ()’ 代替。
                                                                                                                      
                                                                                                                      1
                                                                                                                      2
                                                                                                                      3
                                                                                                                      4
                                                                                                                      5
                                                                                                                      6
                                                                                                                      7
                                                                                                                      8
                                                                                                                      9
                                                                                                                      10
                                                                                                                      • 让变量名与函数名相同。 这会使得脚本的可读性变得很差。
                                                                                                                      do_something ()
                                                                                                                      {
                                                                                                                        echo "This function does something with \"$1\"."
                                                                                                                      }
                                                                                                                      
                                                                                                                      do_something=do_something
                                                                                                                      
                                                                                                                      do_something do_something
                                                                                                                      
                                                                                                                      # 这么做是合法的,但会让人混淆。
                                                                                                                      
                                                                                                                      1
                                                                                                                      2
                                                                                                                      3
                                                                                                                      4
                                                                                                                      5
                                                                                                                      6
                                                                                                                      7
                                                                                                                      8
                                                                                                                      9
                                                                                                                      10
                                                                                                                      • 不合时宜的使用[空白符][1]。与其他编程语言相比,Bash非常讲究空白符的使用。
                                                                                                                      var1 = 23   # ‘var1=23’才是正确的。
                                                                                                                      # 对于上边这一行来说,Bash会把“var1”当作命令来执行,
                                                                                                                      # “=”和“23”会被看作“命令”“var1”的参数。
                                                                                                                      	
                                                                                                                      let c = $a - $b   # ‘let c=$a-$b’或‘let "c = $a - $b"’才是正确的。
                                                                                                                      
                                                                                                                      if [ $a -le 5]    # if [ $a -le 5 ]   是正确的。
                                                                                                                      #           ^^      if [ "$a" -le 5 ]   这么写更好。
                                                                                                                                        # [[ $a -le 5 ]] 也行。
                                                                                                                      
                                                                                                                      1
                                                                                                                      2
                                                                                                                      3
                                                                                                                      4
                                                                                                                      5
                                                                                                                      6
                                                                                                                      7
                                                                                                                      8
                                                                                                                      9
                                                                                                                      • 在[大括号包含的代码块][2]中,最后一条命令没有以[分号][3]结尾。
                                                                                                                      { ls -l; df; echo "Done." }
                                                                                                                      # bash: syntax error: unexpected end of file
                                                                                                                      
                                                                                                                      { ls -l; df; echo "Done."; }
                                                                                                                      #                        ^     ### 最后的这条命令必须以分号结尾。
                                                                                                                      
                                                                                                                      1
                                                                                                                      2
                                                                                                                      3
                                                                                                                      4
                                                                                                                      5
                                                                                                                      • 假定未被初始化的变量(赋值前的变量)被“清0”。事实上,未初始化的变量值为“null”,而不是0。
                                                                                                                      #!/bin/bash
                                                                                                                      
                                                                                                                      echo "uninitialized_var = $uninitialized_var"
                                                                                                                      # uninitialized_var =
                                                                                                                      
                                                                                                                      # 但是 . . .
                                                                                                                      # if $BASH_VERSION ≥ 4.2; then
                                                                                                                      
                                                                                                                      if [[ ! -v uninitialized_var ]]
                                                                                                                      then
                                                                                                                        uninitialized_var=0   # Initialize it to zero!
                                                                                                                      fi
                                                                                                                      
                                                                                                                      
                                                                                                                      
                                                                                                                      1
                                                                                                                      2
                                                                                                                      3
                                                                                                                      4
                                                                                                                      5
                                                                                                                      6
                                                                                                                      7
                                                                                                                      8
                                                                                                                      9
                                                                                                                      10
                                                                                                                      11
                                                                                                                      12
                                                                                                                      13
                                                                                                                      14
                                                                                                                      • 混淆测试符号=和-ep。请记住,=用于比较字符变量,而-ep用来比较整数。
                                                                                                                      if [ "$a" = 273 ]      # $a是整数还是字符串?
                                                                                                                      if [ "$a" -eq 273 ]    # $a为整数。
                                                                                                                      
                                                                                                                      # 有些情况下,即使你混用-ep和=,也不会产生错误的结果。
                                                                                                                      # 然而 . . .
                                                                                                                      
                                                                                                                      
                                                                                                                      a=273.0   # 不是一个整数。
                                                                                                                      	   
                                                                                                                      if [ "$a" = 273 ]
                                                                                                                      then
                                                                                                                        echo "Comparison works."
                                                                                                                      else  
                                                                                                                        echo "Comparison does not work."
                                                                                                                      fi    # Comparison does not work.
                                                                                                                      
                                                                                                                      # 与a=" 273"和a="0273"相同。
                                                                                                                      
                                                                                                                      
                                                                                                                      # 类似的, 如果对非整数值使用“-ep”的话,就会产生问题。
                                                                                                                      	   
                                                                                                                      if [ "$a" -eq 273.0 ]
                                                                                                                      then
                                                                                                                        echo "a = $a"
                                                                                                                      fi  # 产生了错误消息而退出。
                                                                                                                      # test.sh: [: 273.0: integer expression expected
                                                                                                                      
                                                                                                                      1
                                                                                                                      2
                                                                                                                      3
                                                                                                                      4
                                                                                                                      5
                                                                                                                      6
                                                                                                                      7
                                                                                                                      8
                                                                                                                      9
                                                                                                                      10
                                                                                                                      11
                                                                                                                      12
                                                                                                                      13
                                                                                                                      14
                                                                                                                      15
                                                                                                                      16
                                                                                                                      17
                                                                                                                      18
                                                                                                                      19
                                                                                                                      20
                                                                                                                      21
                                                                                                                      22
                                                                                                                      23
                                                                                                                      24
                                                                                                                      25
                                                                                                                      26
                                                                                                                      • 误用了[字符串比较][4]操作符。

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

                                                                                                                      #!/bin/bash
                                                                                                                      # bad-op.sh: 尝试一下对整数使用字符串比较。
                                                                                                                      
                                                                                                                      echo
                                                                                                                      number=1
                                                                                                                      
                                                                                                                      #  下面的"while循环"有两个过错误:
                                                                                                                      #+ 一个比较明显,而另一个比较隐蔽。
                                                                                                                      
                                                                                                                      while [ "$number" < 5 ]    # 错!应该是:  while [ "$number" -lt 5 ]
                                                                                                                      do
                                                                                                                        echo -n "$number "
                                                                                                                        let "number += 1"
                                                                                                                      done  
                                                                                                                      #  如果试图运行这个错误的脚本,就会得到一个错误信息:
                                                                                                                      #+ bad-op.sh: line 10: 5: No such file or directory
                                                                                                                      #  在单中括号结构([ ])中,"<"必须被转义,
                                                                                                                      #+ 即便如此,比较两个整数仍是错误的。
                                                                                                                      
                                                                                                                      echo "---------------------"
                                                                                                                      
                                                                                                                      while [ "$number" \< 5 ]    #  1 2 3 4
                                                                                                                      do                          #
                                                                                                                        echo -n "$number "        #  看起来好像可以工作,但是 . . .
                                                                                                                        let "number += 1"         #+ 事实上是比较ASCII码,
                                                                                                                        done                      #+ 而不是整数比较。
                                                                                                                      
                                                                                                                      echo; echo "---------------------"
                                                                                                                      
                                                                                                                      # 这么做会产生问题。比如:
                                                                                                                      
                                                                                                                      lesser=5
                                                                                                                      greater=105
                                                                                                                      
                                                                                                                      if [ "$greater" \< "$lesser" ]
                                                                                                                      then
                                                                                                                        echo "$greater is less than $lesser"
                                                                                                                      fi                          # 105 is less than 5
                                                                                                                      #  事实上,在字符串比较中(按照ASCII码的顺序)
                                                                                                                      #+ "105"小于"5"。
                                                                                                                      
                                                                                                                      echo
                                                                                                                      
                                                                                                                      exit 0
                                                                                                                      
                                                                                                                      1
                                                                                                                      2
                                                                                                                      3
                                                                                                                      4
                                                                                                                      5
                                                                                                                      6
                                                                                                                      7
                                                                                                                      8
                                                                                                                      9
                                                                                                                      10
                                                                                                                      11
                                                                                                                      12
                                                                                                                      13
                                                                                                                      14
                                                                                                                      15
                                                                                                                      16
                                                                                                                      17
                                                                                                                      18
                                                                                                                      19
                                                                                                                      20
                                                                                                                      21
                                                                                                                      22
                                                                                                                      23
                                                                                                                      24
                                                                                                                      25
                                                                                                                      26
                                                                                                                      27
                                                                                                                      28
                                                                                                                      29
                                                                                                                      30
                                                                                                                      31
                                                                                                                      32
                                                                                                                      33
                                                                                                                      34
                                                                                                                      35
                                                                                                                      36
                                                                                                                      37
                                                                                                                      38
                                                                                                                      39
                                                                                                                      40
                                                                                                                      41
                                                                                                                      42
                                                                                                                      43
                                                                                                                      44
                                                                                                                      • 试图用[let][5]来设置字符串变量。
                                                                                                                      let "a = hello, you"
                                                                                                                      echo "$a"   # 0
                                                                                                                      
                                                                                                                      1
                                                                                                                      2
                                                                                                                      • 有时候在“test”中括号([ ])结构里的变量需要被引用起来(双引号)。如果不这么做的话,可能会引起不可预料的结果。请参考[例子 7-6][6],[例子 16-5][7],[例子 9-6][8]。

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

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

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

                                                                                                                      command1 2> - | command2
                                                                                                                      # 试图将command1的错误输出重定向到一个管道中 . . .
                                                                                                                      # . . . 不会工作。
                                                                                                                      
                                                                                                                      command1 2>& - | command2  # 也没效果。
                                                                                                                      
                                                                                                                      感谢,S.C。
                                                                                                                      
                                                                                                                      1
                                                                                                                      2
                                                                                                                      3
                                                                                                                      4
                                                                                                                      5
                                                                                                                      6
                                                                                                                      7
                                                                                                                      • 使用[Bash 2.0或更高版本][11]的功能,可以在产生错误信息的时候,引发修复动作。但是比较老的Linux机器默认安装的可能是Bash 1.XX。
                                                                                                                      #!/bin/bash
                                                                                                                      
                                                                                                                      minimum_version=2
                                                                                                                      # 因为Chet Ramey经常给Bash添加一些新的特征,
                                                                                                                      # 所以你最好将$minimum_version设置为2.XX,3.XX,或是其他你认为比较合适的值。
                                                                                                                      E_BAD_VERSION=80
                                                                                                                      
                                                                                                                      if [ "$BASH_VERSION" \< "$minimum_version" ]
                                                                                                                      then
                                                                                                                        echo "This script works only with Bash, version $minimum or greater."
                                                                                                                        echo "Upgrade strongly recommended."
                                                                                                                        exit $E_BAD_VERSION
                                                                                                                      fi
                                                                                                                      
                                                                                                                      ...
                                                                                                                      
                                                                                                                      1
                                                                                                                      2
                                                                                                                      3
                                                                                                                      4
                                                                                                                      5
                                                                                                                      6
                                                                                                                      7
                                                                                                                      8
                                                                                                                      9
                                                                                                                      10
                                                                                                                      11
                                                                                                                      12
                                                                                                                      13
                                                                                                                      14
                                                                                                                      15
                                                                                                                      • 在非Linux机器上的[Bourne shell][12]脚本( #!/bin/sh )中使用Bash特有的功能,[可能会引起不可预料的行为][13]。Linux系统通常都会把bash别名化为sh,但是在一般的UNIX机器上却不一定会这么做。

                                                                                                                      • 使用Bash未文档化的特征,将是一种危险的举动。本书之前的几个版本就依赖一个这种“特征”,下面说明一下这个“特征”,虽然[exit][14]或[return][15]所能返回的最大正值为255,但是并没有限制我们使用负整数。不幸的是, Bash 2.05b之后的版本,这个漏洞消失了。请参考[例子 24-9][16]。

                                                                                                                      • 在某些情况下,会返回一个误导性的[退出状态][17]。[设置一个函数内的局部变量][18]或[分配一个算术值给一个变量][19]时,就有可能发生这种情况。

                                                                                                                      • [算术表达式的退出状态][20]不等同于一个错误代码。

                                                                                                                      var=1 && ((--var)) && echo $var
                                                                                                                      #        ^^^^^^^^^ 在这里,这个与列表返回错误代码1而终止。
                                                                                                                      #                     不会打印$var的值!
                                                                                                                      echo $?   # 1
                                                                                                                      
                                                                                                                      1
                                                                                                                      2
                                                                                                                      3
                                                                                                                      4
                                                                                                                      • 一个带有DOS风格换行符(\r\n)的脚本将会运行失败,因为**#!/bin/bash\r\n是不合法的,与我们所期望的#!/bin/bash\n**不同,解决办法就是将这个脚本转换为UNIX风格的换行符。
                                                                                                                      #!/bin/bash
                                                                                                                      
                                                                                                                      echo "Here"
                                                                                                                      
                                                                                                                      unix2dos $0    # 脚本先将自己改为DOS格式。
                                                                                                                      chmod 755 $0   # 更改可执行权限。
                                                                                                                                     # 'unix2dos'会删除可执行权限
                                                                                                                      
                                                                                                                      ./$0           # 脚本尝试再次运行自己。
                                                                                                                                     # 但它作为一个DOS文件,已经不能运行了。
                                                                                                                      
                                                                                                                      echo "There"
                                                                                                                      
                                                                                                                      exit 0
                                                                                                                      
                                                                                                                      1
                                                                                                                      2
                                                                                                                      3
                                                                                                                      4
                                                                                                                      5
                                                                                                                      6
                                                                                                                      7
                                                                                                                      8
                                                                                                                      9
                                                                                                                      10
                                                                                                                      11
                                                                                                                      12
                                                                                                                      13
                                                                                                                      14
                                                                                                                      • 以**#!/bin/sh开头的Bash脚本,不能在完整的Bash兼容模式下运行。某些Bash特定的功能可能会被禁用。如果脚本需要完整的访问所有Bash专有扩展,那么它需要使用#!/bin/bash**作为开头。

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

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

                                                                                                                      add2 ()
                                                                                                                      {
                                                                                                                        echo "Whatever ... "   # 删掉zhehan
                                                                                                                        let "retval = $1 + $2"
                                                                                                                          echo $retval
                                                                                                                          }
                                                                                                                      
                                                                                                                          num1=12
                                                                                                                          num2=43
                                                                                                                          echo "Sum of $num1 and $num2 = $(add2 $num1 $num2)"
                                                                                                                      
                                                                                                                      #   Sum of 12 and 43 = Whatever ... 
                                                                                                                      #   55
                                                                                                                      
                                                                                                                      #        这些echo连在一起了。
                                                                                                                      
                                                                                                                      1
                                                                                                                      2
                                                                                                                      3
                                                                                                                      4
                                                                                                                      5
                                                                                                                      6
                                                                                                                      7
                                                                                                                      8
                                                                                                                      9
                                                                                                                      10
                                                                                                                      11
                                                                                                                      12
                                                                                                                      13
                                                                                                                      14
                                                                                                                      15

                                                                                                                      这是[行不通][24]的。

                                                                                                                      • 脚本不能将变量export到它的[父进程]25,或父进程的环境中。就好比我们在生物学中所学到的那样,子进程只会继承父进程, 反过来则不行。
                                                                                                                      WHATEVER=/home/bozo
                                                                                                                      export WHATEVER
                                                                                                                      exit 0
                                                                                                                      
                                                                                                                      1
                                                                                                                      2
                                                                                                                      3
                                                                                                                      bash$ echo $WHATEVER
                                                                                                                      bash$
                                                                                                                      
                                                                                                                      1
                                                                                                                      2
                                                                                                                      • 可以确定的是,即使回到命令行提示符,变量$WHATEVER仍然没有被设置。

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

                                                                                                                      样例 34-2. 子shell缺陷

                                                                                                                      #!/bin/bash
                                                                                                                      # 子shell中的变量缺陷。
                                                                                                                      
                                                                                                                      outer_variable=outer
                                                                                                                      echo
                                                                                                                      echo "outer_variable = $outer_variable"
                                                                                                                      echo
                                                                                                                      
                                                                                                                      (
                                                                                                                      # 开始子shell
                                                                                                                      
                                                                                                                      echo "outer_variable inside subshell = $outer_variable"
                                                                                                                      inner_variable=inner  # Set
                                                                                                                      echo "inner_variable inside subshell = $inner_variable"
                                                                                                                      outer_variable=inner  # 会修改全局变量吗?
                                                                                                                      echo "outer_variable inside subshell = $outer_variable"
                                                                                                                      
                                                                                                                      # 如果将变量‘导出’会产生不同的结果么?
                                                                                                                      #    export inner_variable
                                                                                                                      #    export outer_variable
                                                                                                                      # 试试看。
                                                                                                                      
                                                                                                                      # 结束子shell
                                                                                                                      )
                                                                                                                      
                                                                                                                      echo
                                                                                                                      echo "inner_variable outside subshell = $inner_variable"  # Unset.
                                                                                                                      echo "outer_variable outside subshell = $outer_variable"  # Unchanged.
                                                                                                                      echo
                                                                                                                      
                                                                                                                      exit 0
                                                                                                                      
                                                                                                                      # 如果你去掉第19和第20行的注释会怎样?
                                                                                                                      # 会产生不同的结果吗?
                                                                                                                      
                                                                                                                      1
                                                                                                                      2
                                                                                                                      3
                                                                                                                      4
                                                                                                                      5
                                                                                                                      6
                                                                                                                      7
                                                                                                                      8
                                                                                                                      9
                                                                                                                      10
                                                                                                                      11
                                                                                                                      12
                                                                                                                      13
                                                                                                                      14
                                                                                                                      15
                                                                                                                      16
                                                                                                                      17
                                                                                                                      18
                                                                                                                      19
                                                                                                                      20
                                                                                                                      21
                                                                                                                      22
                                                                                                                      23
                                                                                                                      24
                                                                                                                      25
                                                                                                                      26
                                                                                                                      27
                                                                                                                      28
                                                                                                                      29
                                                                                                                      30
                                                                                                                      31
                                                                                                                      32
                                                                                                                      33
                                                                                                                      34
                                                                                                                      • 将echo的输出通过[管道][27]传递给[read][28]命令可能会产生不可预料的结果。在这种情况下,read命令的行为就好像它在子shell中运行一样。可以使用[set][29]命令来代替(就好像[例子15-18][30]一样)。

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

                                                                                                                      #!/bin/bash
                                                                                                                      #  badread.sh:
                                                                                                                      #  尝试使用'echo'和'read'命令
                                                                                                                      #+ 非交互的给变量赋值。
                                                                                                                      
                                                                                                                      #   shopt -s lastpipe
                                                                                                                      
                                                                                                                      a=aaa
                                                                                                                      b=bbb
                                                                                                                      c=ccc
                                                                                                                      
                                                                                                                      echo "one two three" | read a b c
                                                                                                                      # 尝试重新给变量a,b,和c赋值。
                                                                                                                      
                                                                                                                      echo
                                                                                                                      echo "a = $a"  # a = aaa
                                                                                                                      echo "b = $b"  # b = bbb
                                                                                                                      echo "c = $c"  # c = ccc
                                                                                                                      # 重新赋值失败。
                                                                                                                      
                                                                                                                      ### 但如果 . . .
                                                                                                                      ##  去掉第6行的注释:
                                                                                                                      #   shopt -s lastpipe
                                                                                                                      ##+ 就能解决这个问题!
                                                                                                                      ### 这是Bash 4.2版本的新特性。
                                                                                                                      
                                                                                                                      # ------------------------------
                                                                                                                      
                                                                                                                      # 试试下边这种方法。
                                                                                                                      
                                                                                                                      var=`echo "one two three"`
                                                                                                                      set -- $var
                                                                                                                      a=$1; b=$2; c=$3
                                                                                                                      
                                                                                                                      echo "-------"
                                                                                                                      echo "a = $a"  # a = one
                                                                                                                      echo "b = $b"  # b = two
                                                                                                                      echo "c = $c"  # c = three 
                                                                                                                      # 重新赋值成功。
                                                                                                                      
                                                                                                                      # ------------------------------
                                                                                                                      
                                                                                                                      #  也请注意,echo到'read'的值只会在子shell中起作用。
                                                                                                                      #  所以,变量的值*只*会在子shell中被修改。
                                                                                                                      
                                                                                                                      a=aaa          # 重新开始。
                                                                                                                      b=bbb
                                                                                                                      c=ccc
                                                                                                                      
                                                                                                                      echo; echo
                                                                                                                      echo "one two three" | ( read a b c;
                                                                                                                      echo "Inside subshell: "; echo "a = $a"; echo "b = $b"; echo "c = $c" )
                                                                                                                      # a = one
                                                                                                                      # b = two
                                                                                                                      # c = three
                                                                                                                      echo "-----------------"
                                                                                                                      echo "Outside subshell: "
                                                                                                                      echo "a = $a"  # a = aaa
                                                                                                                      echo "b = $b"  # b = bbb
                                                                                                                      echo "c = $c"  # c = ccc
                                                                                                                      echo
                                                                                                                      
                                                                                                                      exit 0
                                                                                                                      
                                                                                                                      1
                                                                                                                      2
                                                                                                                      3
                                                                                                                      4
                                                                                                                      5
                                                                                                                      6
                                                                                                                      7
                                                                                                                      8
                                                                                                                      9
                                                                                                                      10
                                                                                                                      11
                                                                                                                      12
                                                                                                                      13
                                                                                                                      14
                                                                                                                      15
                                                                                                                      16
                                                                                                                      17
                                                                                                                      18
                                                                                                                      19
                                                                                                                      20
                                                                                                                      21
                                                                                                                      22
                                                                                                                      23
                                                                                                                      24
                                                                                                                      25
                                                                                                                      26
                                                                                                                      27
                                                                                                                      28
                                                                                                                      29
                                                                                                                      30
                                                                                                                      31
                                                                                                                      32
                                                                                                                      33
                                                                                                                      34
                                                                                                                      35
                                                                                                                      36
                                                                                                                      37
                                                                                                                      38
                                                                                                                      39
                                                                                                                      40
                                                                                                                      41
                                                                                                                      42
                                                                                                                      43
                                                                                                                      44
                                                                                                                      45
                                                                                                                      46
                                                                                                                      47
                                                                                                                      48
                                                                                                                      49
                                                                                                                      50
                                                                                                                      51
                                                                                                                      52
                                                                                                                      53
                                                                                                                      54
                                                                                                                      55
                                                                                                                      56
                                                                                                                      57
                                                                                                                      58
                                                                                                                      59
                                                                                                                      60
                                                                                                                      61
                                                                                                                      62
                                                                                                                      63

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

                                                                                                                      # 循环的管道问题。
                                                                                                                      #  这个例子由Anthony Richardson编写,
                                                                                                                      #+ 由Wilbert Berendsen补遗。
                                                                                                                      
                                                                                                                      
                                                                                                                      foundone=false
                                                                                                                      find $HOME -type f -atime +30 -size 100k |
                                                                                                                      while true
                                                                                                                      do
                                                                                                                         read f
                                                                                                                         echo "$f is over 100KB and has not been accessed in over 30 days"
                                                                                                                         echo "Consider moving the file to archives."
                                                                                                                         foundone=true
                                                                                                                         # ------------------------------------
                                                                                                                           echo "Subshell level = $BASH_SUBSHELL"
                                                                                                                         # Subshell level = 1
                                                                                                                         # 没错, 现在是在子shell中运行。
                                                                                                                         # ------------------------------------
                                                                                                                      done
                                                                                                                         
                                                                                                                      #  变量foundone在这里肯定是false,
                                                                                                                      #+ 因为它是在子shell中被设置为true的。
                                                                                                                      if [ $foundone = false ]
                                                                                                                      then
                                                                                                                         echo "No files need archiving."
                                                                                                                      fi
                                                                                                                      
                                                                                                                      # =====================现在,下边是正确的方法:=================
                                                                                                                      
                                                                                                                      foundone=false
                                                                                                                      for f in $(find $HOME -type f -atime +30 -size 100k)  # 这里没使用管道。
                                                                                                                      do
                                                                                                                         echo "$f is over 100KB and has not been accessed in over 30 days"
                                                                                                                         echo "Consider moving the file to archives."
                                                                                                                         foundone=true
                                                                                                                      done
                                                                                                                         
                                                                                                                      if [ $foundone = false ]
                                                                                                                      then
                                                                                                                         echo "No files need archiving."
                                                                                                                      fi
                                                                                                                      
                                                                                                                      # ==================这里是另一种方法==================
                                                                                                                      
                                                                                                                      #  将脚本中读取变量的部分放到一个代码块中,
                                                                                                                      #+ 这样一来,它们就能在相同的子shell中共享了。
                                                                                                                      #  感谢,W.B。
                                                                                                                      
                                                                                                                      find $HOME -type f -atime +30 -size 100k | {
                                                                                                                           foundone=false
                                                                                                                           while read f
                                                                                                                           do
                                                                                                                             echo "$f is over 100KB and has not been accessed in over 30 days"
                                                                                                                             echo "Consider moving the file to archives."
                                                                                                                             foundone=true
                                                                                                                           done
                                                                                                                      
                                                                                                                           if ! $foundone
                                                                                                                           then
                                                                                                                             echo "No files need archiving."
                                                                                                                           fi
                                                                                                                      }
                                                                                                                      
                                                                                                                      1
                                                                                                                      2
                                                                                                                      3
                                                                                                                      4
                                                                                                                      5
                                                                                                                      6
                                                                                                                      7
                                                                                                                      8
                                                                                                                      9
                                                                                                                      10
                                                                                                                      11
                                                                                                                      12
                                                                                                                      13
                                                                                                                      14
                                                                                                                      15
                                                                                                                      16
                                                                                                                      17
                                                                                                                      18
                                                                                                                      19
                                                                                                                      20
                                                                                                                      21
                                                                                                                      22
                                                                                                                      23
                                                                                                                      24
                                                                                                                      25
                                                                                                                      26
                                                                                                                      27
                                                                                                                      28
                                                                                                                      29
                                                                                                                      30
                                                                                                                      31
                                                                                                                      32
                                                                                                                      33
                                                                                                                      34
                                                                                                                      35
                                                                                                                      36
                                                                                                                      37
                                                                                                                      38
                                                                                                                      39
                                                                                                                      40
                                                                                                                      41
                                                                                                                      42
                                                                                                                      43
                                                                                                                      44
                                                                                                                      45
                                                                                                                      46
                                                                                                                      47
                                                                                                                      48
                                                                                                                      49
                                                                                                                      50
                                                                                                                      51
                                                                                                                      52
                                                                                                                      53
                                                                                                                      54
                                                                                                                      55
                                                                                                                      56
                                                                                                                      57
                                                                                                                      58
                                                                                                                      59
                                                                                                                      60
                                                                                                                      61
                                                                                                                      62
                                                                                                                      • 一个相关的问题:当你尝试将tail -f的stdout通过管道传递给[grep][31]时,会产生问题。
                                                                                                                      tail -f /var/log/messages | grep "$ERROR_MSG" >> error.log
                                                                                                                      #  “error.log”文件将不会写入任何东西。
                                                                                                                      #  正如Samuli Kaipiainen指出的那样,
                                                                                                                      #+ 这一结果是从grep的缓冲区输出的。
                                                                                                                      #  解决的办法就是把“--line-buffered”参数添加到grep中。
                                                                                                                      
                                                                                                                      1
                                                                                                                      2
                                                                                                                      3
                                                                                                                      4
                                                                                                                      5
                                                                                                                      • 在脚本中使用“suid”命令是非常危险的,因为这会危及系统安全。[1]

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

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

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

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

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

                                                                                                                      ——A.J. Lamb and H.W. Petrie [1]: http://tldp.org/LDP/abs/html/special-chars.html#WHITESPACEREF [2]: http://tldp.org/LDP/abs/html/special-chars.html#CODEBLOCKREF [3]: http://tldp.org/LDP/abs/html/special-chars.html#SEMICOLONREF [4]: http://tldp.org/LDP/abs/html/comparison-ops.html#SCOMPARISON1 [5]: http://tldp.org/LDP/abs/html/internal.html#LETREF [6]: http://tldp.org/LDP/abs/html/comparison-ops.html#STRTEST [7]: http://tldp.org/LDP/abs/html/redircb.html#REDIR2 [8]: http://tldp.org/LDP/abs/html/internalvariables.html#ARGLIST [9]: http://tldp.org/LDP/abs/html/quotingvar.html#WSQUO [10]: http://tldp.org/LDP/abs/html/quotingvar.html#VARSPLITTING [11]: http://tldp.org/LDP/abs/html/bashver2.html#BASH2REF [12]: http://tldp.org/LDP/abs/html/why-shell.html#BASHDEF [13]: http://tldp.org/LDP/abs/html/gotchas.html#BINSH [14]: http://tldp.org/LDP/abs/html/exit-status.html#EXITSTATUSREF [15]: http://tldp.org/LDP/abs/html/complexfunct.html#RETURNREF [16]: http://tldp.org/LDP/abs/html/complexfunct.html#RETURNTEST [17]: http://tldp.org/LDP/abs/html/exit-status.html#EXITSTATUSREF [18]: http://tldp.org/LDP/abs/html/localvar.html#EXITVALANOMALY01 [19]: http://tldp.org/LDP/abs/html/internal.html#EXITVALANOMALY02 [20]: http://tldp.org/LDP/abs/html/testconstructs.html#ARXS [21]: http://tldp.org/LDP/abs/html/here-docs.html#HEREDOCREF [22]: http://tldp.org/LDP/abs/html/here-docs.html#INDENTEDLS [23]: http://tldp.org/LDP/abs/html/assortedtips.html#RVT [24]: http://tldp.org/LDP/abs/html/assortedtips.html#RVTCAUTION [25]: http://tldp.org/LDP/abs/html/internal.html#FORKREF [26]: http://tldp.org/LDP/abs/html/subshells.html#SUBSHELLSREF [27]: http://tldp.org/LDP/abs/html/special-chars.html#PIPEREF [28]: http://tldp.org/LDP/abs/html/internal.html#READREF [29]: http://tldp.org/LDP/abs/html/internal.html#SETREF [30]: http://tldp.org/LDP/abs/html/internal.html#SETPOS [31]: http://tldp.org/LDP/abs/html/textproc.html#GREPREF [32]: http://tldp.org/LDP/abs/html/internal.html#DOUBLESLASHREF [33]: http://tldp.org/LDP/abs/html/textproc.html#TRREF [34]: http://tldp.org/LDP/abs/html/string-manipulation.html#PARAGRAPHSPACE [35]: http://tldp.org/LDP/abs/html/gotchas.html#UNDOCF [36]: http://tldp.org/LDP/abs/html/fto.html#SUIDREF

                                                                                                                      # 注意事项


                                                                                                                      1. 在Linux和绝大多数的UNIX机器上,给脚本设置[suid][36]权限是没用的。 ↩︎

                                                                                                                      edit icon编辑此页open in new window
                                                                                                                      上次编辑于: 2022/4/27 15:33:00
                                                                                                                      贡献者: clay-wangzhi
                                                                                                                      上一页
                                                                                                                      33 选项
                                                                                                                      下一页
                                                                                                                      第36章 杂项
                                                                                                                      备案号:冀ICP备2021007336号
                                                                                                                      Copyright © 2023 LinuxStory