我们采用Red Hat Linux和Unix下面广泛使用的BASH来编写脚本。首先讲解有关Here Documents的语法基础和基本使用方法。
3.1 语法结构
在命令行中执行man bash,可以找到BASH手册中有关Here Documents的语法定义,其一般形式如下:
为了便于说明,这段说明翻译成中文如下所示:#man bash
![]()
Here Documents
This type of redirection instructs the shell to read input from the
current source until a line containing only word (with no trailing
blanks) is seen. All of the lines read up to that point are then used
as the standard input for a command.
![]()
The format of here-documents is:
![]()
<<[-]word
here-document
delimiter
![]()
No parameter expansion, command substitution, arithmetic expansion, or
pathname expansion is performed on word. If any characters in word are
quoted, the delimiter is the result of quote removal on word, and the
lines in the here-document are not expanded. If word is unquoted, all
lines of the here-document are subjected to parameter expansion, com-
mand substitution, and arithmetic expansion. In the latter case, the
character sequence \<newline> is ignored, and \ must be used to quote
the characters \, $, and `.
![]()
If the redirection operator is <<-, then all leading tab characters are
stripped from input lines and the line containing delimiter. This
allows here-documents within shell scripts to be indented in a natural
fashion.
#man bash
![]()
Here Documents(嵌入文档)
Here Documents作为重定向的一种方式,指示shell从源文件的
当前位置开始读取输出,直 到遇到只包含一个单词的文本行时结束。
在该过程中读到的所有文本行都将作为某一个命令的标准输入而使用。here-documents的使用形式:
![]()
<<[-]word
here-document
delimiter
![]()
Shell将不对word 进行任何参数和命令替换、表达式计算,以及文件名扩展。
如果在word中出现被引号包含的字符,则delimiter 将被视为在word中去除
引号所包含部分的结果,并且here-document中的文本将不被扩展。如果word
不包含引号,则here-document中的所有文本都将进行常规的参数扩展、命令
替换、表达式计算。在后一种情况下,字符序列\<newline>将被忽略, 并且必
须对元字符\, $, 和`使用\进行转义。如果重定向操作符是<<-, 则输入行和delimiter行中的所有前缀TAB字符
都将被忽略。这样源代码中的here-documents就可以按照优雅的嵌入方式进行对齐。
3.2 技术的应用
下面我们考察一下在Shell脚本中使用Here Documents的必要性所在。Shell脚本对于文本文件的处理是非常方便的,因此实现本文所要完成的工作还是比较简单的,只需对所有文件进行一次循环过程。但是问题在于,从①-②,②-③的每一部,实际上都是使用cut、echo、cat等进行流处理,每个处理过程的输出作为下一步骤的输出。这里面自然的要使用重定向的方法。在以前对BASH用的不熟的时候,往往笨拙的使用临时文件存储这些中间结果。比如: 00000004.REG -> 00000004.cut -> 00000004.line -> all.txt。这样处理的过程中,代码显的非常杂乱,而且有时候不得不写出多个脚本来处理重定向,这种情况使得问题更为加重。
因此,这次下决心要将代码写的精简一些。在BASH内部可以使用Here Documents进行重定向,使流的输入输出都是在同一脚本内进行的,不用拆开成多个脚本,也省略了大量的中间文件,使代码非常清晰、紧凑。
Here Documents的一般形式如下:
在上面这个语法描述中,0001行的commands是任何SHELL命令。ID是一个字符串标识,标志着嵌入文档的开始(习惯上,常用的标识是EOF,等等)。从0002行可以写任何文本,这里写入的内容都将作为标准输入传送给commands。在最后一行写标识符ID,代码嵌入文本结束。0001 commands <<ID
0002 here documents
....... ......
000n ID<\n>
在使用Here Documents编写脚本的时候注意以下两点:
1. 在000n行上,必须只有一个ID,也就是说,ID前面不能有空格,ID后面必须是回车符。否则SHELL处理时会出错。这一点在实际时要尤为注意。
2. 嵌入文档内可以写普通文本(比如说,写程序的使用Usage),也可以是标准的SHELL语句。如果是SHELL语句,要使用反引号(`)括起来,这时候语句的标准输出也将作为嵌入文档送给commands。这个特性非常有用。
下面举一个简单的例子:
上面是一个最简单的例子,但是已经基本概括了Here Documents的使用方法。在aa.sh中,EOF作为嵌入文档的标识ID。4、5行中的Here Documents是一行标准文本“Now”和一个命令date的输出。两部分输出送给了cat命令去执行。[exam@Exam-Server user]$ nl -b a aa.sh
1 #!/bin/bash
2
3 cat <<EOF
4 Now:
5 `date`
6 EOF
[exam@Exam-Server user]$ sh aa.sh
Now:
三 7月 26 19:23:24 CST 2006
