一、Here Documents(嵌入文檔)
Here Documents作為重新導向的一種方式,指示shell從源檔案的當前位置開始讀取輸出,直到遇到只包含一個單詞的文本行時結束。在該過程中讀到的所有文本行都將作為某一個命令的標準輸入而使用。
here-documents的使用形式:
command <<[-] limit_string
msg_body
limit_string
如果用雙引號或單引號將”limit_string”引用起來或用轉義符\將其轉義,則here-document中的文本將不被擴充,即參數替換被禁用。否則,here-document中的所有文本都將進行常規的參數擴充、命令替換、運算式計算。在後一種情況下,字元序列\<newline>將被忽略, 並且必須對元字元\, $, 和`使用\進行轉義。
如果用<<而不是<<-,則後面的limit_string必須位於行首,否則,若here_document用在函數內部,則會報語法錯誤;用在函數外面,其後面的所有內容均會被當做here_document的內容。
如果重新導向操作符是<<-, 則msg_body和limit_string行中的所有首碼TAB字元都將被忽略(但空格不會被忽略)。這樣原始碼中的here-documents就可以按照優雅的嵌入方式進行對齊。
二、技術的應用
下面我們考察一下在Shell指令碼中使用Here Documents的必要性所在。Shell指令碼對於文字檔的處理是非常方便的,因此實現本文所要完成的工作還是比較簡單的,只需對所有檔案進行一次迴圈過程。但是問題在於,從①-②,②-③的每一部,實際上都是使用cut、echo、cat等進行流處理,每個處理過程的輸出作為下一步驟的輸出。這裡面自然的要使用重新導向的方法。在以前對BASH用的不熟的時候,往往笨拙的使用臨時檔案儲存體這些中間結果。比如: 00000004.REG -> 00000004.cut-> 00000004.line -> all.txt。這樣處理的過程中,代碼顯的非常雜亂,而且有時候不得不寫出多個指令碼來處理重新導向,這種情況使得問題更為加重。
因此,這次下決心要將代碼寫的精簡一些。在BASH內部可以使用Here Documents進行重新導向,使流的輸入輸出都是在同一指令碼內進行的,不用拆開成多個指令碼,也省略了大量的中間檔案,使代碼非常清晰、緊湊。
Here Documents的一般形式如下:
0001 commands <<ID
0002 here documents
....... ......
000n ID<\n>
在上面這個文法描述中,0001行的commands是任何SHELL命令。ID是一個字串標識,標誌著嵌入文檔的開始(習慣上,常用的標識是EOF,等等)。從0002行可以寫任何文本,這裡寫入的內容都將作為標準輸入傳送給commands。在最後一行寫標識符ID,代碼嵌入文本結束。
在使用Here Documents編寫指令碼的時候注意以下兩點:
在000n行上,必須只有一個ID,也就是說,ID前面不能有空格,ID後面必須是斷行符號符。否則SHELL處理時會出錯。這一點在實際時要尤為注意。
當使用 <<- 時, 輸入行和000n行上的ID前的任何TAB字元將會被忽略;
嵌入文檔內可以寫普通文本(比如說,寫程式的使用Usage),也可以是標準的SHELL語句。如果是SHELL語句,要使用反引號(`)括起來,這時候語句的標準輸出也將作為嵌入文檔送給commands。這個特性非常有用。
1. cat用法
[exam@Exam-Server user]$ cat aa.sh
1 #!/bin/bash
2
3 cat<<EOF # cat > file << EOF,則輸出到新檔案中,而不是stdout
4 Now:
5 `date`
6 EOF
[exam@Exam-Server user]$ sh aa.sh
Now:
可以將here_document的輸出儲存到檔案或變數中
variable=$(cat << EOF
Thisvaribale
runsover multiple lines.
EOF)
echo $variable
This varible runs over mutiplelines.
可以用匿名的命令來接收here_document的輸出,該技術可以用來注釋掉代碼塊。
: << EOF
${HOSTNAME?}${USER?}${MAIL?} # 如果其中一個變數沒被設定, 那麼就列印錯誤資訊.
EOF
三 7月 26 19:23:24 CST 2006
上面是一個最簡單的例子,但是已經基本概括了Here Documents的使用方法。在aa.sh中,EOF作為嵌入文檔的標識ID。4、5行中的Here Documents是一行標準文本“Now”和一個命令date的輸出。兩部分輸出送給了cat命令去執行。
2.shell編輯檔案
shell編輯檔案最常用的方法就是echo 字串 >> 檔案。但是要刪除一行怎麼辦。Here Document就搞定了。
經Jeremiah測試,在Here Document中使用vi是不行的。替代方法是使用ed命令。在命令列執行以下:
$ touch base.txt
$ ed base.txt
a
this is line1.
this is line2.
this is line3.
this is line4.
.
wq
先建立一個檔案base.txt,然後ed這個檔案,輸入a表示最後追加,輸入了四行文字。.表示結束輸入。wq表示儲存退出。
那我們再用ed命令,在shell指令碼裡面對這個檔案再次進行操作。如下。
#!/bin/sh
ed base.txt << EOF
3 # 到第3行
d # 刪除該行
i # 本行增加
this is line 3 new. # 新行內容
. # 結束
w
q # wq表示儲存
EOF
執行的結果如下所示。
$ sh ed_file.sh && cat base.txt
60
this is line3.
65
this is line1.
this is line2.
this is line 3 new.
this is line4.
關於ed的操作和參數,可以查看linux協助或去搜尋相關的資料。
3. shell控制資料庫
假設執行下面的操作訪問資料庫。
$ mysql -u root
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 1257
Server version: 5.1.35-community MySQL Community Server (GPL)
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> use mysql
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
mysql> select * from user;
mysql> exit
Bye
如果我們要用shell指令碼訪問,則可以編寫如下的指令碼。
#!/bin/sh
mysql -u root << EOF
use mysql
select * from user;
exit
EOF
執行如下
sh mysql_access.sh
可以看到結果相同。