17.1. Here String

here string可以看成是here document的一种定制形式. 除了COMMAND <<<$WORD, 就什么都没有了, $WORD将被扩展并且被送入COMMANDstdin中.

  1 String="This is a string of words."
  2 
  3 read -r -a Words <<< "$String"
  4 #  "read"命令的-a选项
  5 #+ 将会把结果值按顺序的分配给数组中的每一项. 
  6 
  7 echo "First word in String is:    ${Words[0]}"   # This
  8 echo "Second word in String is:   ${Words[1]}"   # is
  9 echo "Third word in String is:    ${Words[2]}"   # a
 10 echo "Fourth word in String is:   ${Words[3]}"   # string
 11 echo "Fifth word in String is:    ${Words[4]}"   # of
 12 echo "Sixth word in String is:    ${Words[5]}"   # words.
 13 echo "Seventh word in String is:  ${Words[6]}"   # (null)
 14                                                  # $String的结尾. 
 15 
 16 # 感谢, Francisco Lobo的这个建议. 


例子 17-13. 在一个文件的开头添加文本

  1 #!/bin/bash
  2 # prepend.sh: 在文件的开头添加文本. 
  3 #
  4 #  Kenny Stauffer所捐助的脚本例子, 
  5 #+ 本文作者对这个脚本进行了少量修改. 
  6 
  7 
  8 E_NOSUCHFILE=65
  9 
 10 read -p "File: " file   #  'read'命令的-p参数用来显示提示符. 
 11 if [ ! -e "$file" ]
 12 then   # 如果这个文件不存在, 那就进来. 
 13   echo "File $file not found."
 14   exit $E_NOSUCHFILE
 15 fi
 16 
 17 read -p "Title: " title
 18 cat - $file <<<$title > $file.new
 19 
 20 echo "Modified file is $file.new"
 21 
 22 exit 0
 23 
 24 # 下边是'man bash'中的一段: 
 25 # Here String
 26 # 	here document的一种变形,形式如下: 
 27 # 
 28 # 		<<<word
 29 # 
 30 # 	word被扩展并且被提供到command的标准输入中. 


例子 17-14. 分析一个邮箱

  1 #!/bin/bash
  2 #  由Francisco Lobo所提供的脚本, 
  3 #+ 本文作者进行了少量修改和注释. 
  4 #  并且经过授权, 可以使用在本书中.(感谢你!)
  5 
  6 # 这个脚本不能运行于比Bash version 3.0更低的版本中. 
  7 
  8 
  9 E_MISSING_ARG=67
 10 if [ -z "$1" ]
 11 then
 12   echo "Usage: $0 mailbox-file"
 13   exit $E_MISSING_ARG
 14 fi
 15 
 16 mbox_grep()  # 分析邮箱文件.
 17 {
 18     declare -i body=0 match=0
 19     declare -a date sender
 20     declare mail header value
 21 
 22 
 23     while IFS= read -r mail
 24 #         ^^^^                 重新设置$IFS.
 25 #  否则"read"会从它的输入中截去开头和结尾的空格. 
 26 
 27    do
 28        if [[ $mail =~ "^From " ]]   # 匹配消息中的"From"域. 
 29        then
 30           (( body  = 0 ))           # 取消("Zero out"俚语)变量. 
 31           (( match = 0 ))
 32           unset date
 33 
 34        elif (( body ))
 35        then
 36             (( match ))
 37             # echo "$mail"
 38             # 如果你想显示整个消息体的话, 那么就打开上面的注释行. 
 39 
 40        elif [[ $mail ]]; then
 41           IFS=: read -r header value <<< "$mail"
 42           #                          ^^^  "here string"
 43 
 44           case "$header" in
 45           [Ff][Rr][Oo][Mm] ) [[ $value =~ "$2" ]] && (( match++ )) ;;
 46           # 匹配"From"行. 
 47           [Dd][Aa][Tt][Ee] ) read -r -a date <<< "$value" ;;
 48           #                                  ^^^
 49           # 匹配"Date"行. 
 50           [Rr][Ee][Cc][Ee][Ii][Vv][Ee][Dd] ) read -r -a sender <<< "$value" ;;
 51           #                                                    ^^^
 52           # 匹配IP地址(可能被欺骗). 
 53           esac
 54 
 55        else
 56           (( body++ ))
 57           (( match  )) &&
 58           echo "MESSAGE ${date:+of: ${date[*]} }"
 59        #    整个$date数组                  ^
 60           echo "IP address of sender: ${sender[1]}"
 61        #    "Received"行的第二个域             ^
 62 
 63        fi
 64 
 65 
 66     done < "$1" # 将文件的stdout重定向到循环中. 
 67 }
 68 
 69 
 70 mbox_grep "$1"  # 将邮箱文件发送到函数中. 
 71 
 72 exit $?
 73 
 74 # 练习:
 75 # -----
 76 # 1) 拆开上面的这个函数, 把它分成多个函数, 
 77 #+   这样可以提高代码的可读性. 
 78 # 2) 对这个脚本添加额外的分析, 可以分析不同的关键字. 
 79 
 80 
 81 
 82 $ mailbox_grep.sh scam_mail
 83 --> MESSAGE of Thu, 5 Jan 2006 08:00:56 -0500 (EST) 
 84 --> IP address of sender: 196.3.62.4

练习: 找出here string的其他用法.