1、IFS 介紹php
Shell 腳本中有個變量叫 IFS(Internal Field Seprator) ,內部域分隔符。完整定義是The shell uses the value stored in IFS, which is the space, tab, and newline characters by default, to delimit words for the read and set commands, when parsing output from command substitution, and when performing variable substitution.html
Shell 的環境變量分爲 set, env 兩種,其中 set 變量能夠經過 export 工具導入到 env 變量中。其中,set 是顯示設置shell變量,僅在本 shell 中有效;env 是顯示設置用戶環境變量 ,僅在當前會話中有效。換句話說,set 變量裏包含了 env 變量,但 set 變量不必定都是 env 變量。這兩種變量不一樣之處在於變量的做用域不一樣。顯然,env 變量的做用域要大些,它能夠在 subshell 中使用。shell
而 IFS 是一種 set 變量,當 shell 處理"命令替換"和"參數替換"時,shell 根據 IFS 的值,默認是 space, tab, newline 來拆解讀入的變量,而後對特殊字符進行處理,最後從新組合賦值給該變量。bash
2、IFS 簡單實例ide
一、查看變量 IFS 的值。
函數
工具
直接輸出IFS是看不到的,把它轉化爲二進制就能夠看到了,"040"是空格,"011"是Tab,"012"是換行符"\n" 。最後一個 012 是由於 echo 默認是會換行的。
測試
二、$* 和 $@ 的細微差異
從下面的例子中能夠看出,若是是用冒號引發來,表示這個變量不用IFS替換!!因此能夠看到這個變量的"原始值"。反之,若是不加引號,輸出時會根據IFS的值來分割後合併輸出! $* 是按照IFS中的第一個值來肯定的!下面這兩個例子還有細微的差異!
ui
spa
上例 set 變量實際上是3個參數,而下面這個例子實質是2個參數,即 set "x y z" 和 set x y z 是徹底不一樣的。
小結:$* 會根據 IFS 的不一樣來組合值,而 $@ 則會將值用" "來組合值!
三、for 循環中的奇怪現象
先暫且不解釋 for 循環的內容!看下面這個輸出!IFS 的值同上! var=": a:b::c:",
"$var"的值應該沒作替換,因此仍是 ": a:b::c:" (注 "072" 表示冒號),可是$var 則發生了變化!注意輸出的最後一個冒號沒有了,也沒有替換爲空格!Why?
使用 $var 時是經歷了這樣一個過程!首先,按照這樣的規則 [變量][IFS][變量][IFS]……根據原始 var 值中全部的分割符(此處是":")劃分出變量,若是IFS的值是有多個字符組成,如IFS=":;",那麼此處的[IFS]指的是IFS中的任意一個字符($* 是按第一個字符來分隔!),如 ":" 或者 ";" ,後面再也不對[IFS]作相似說明!(注:[IFS]會有多個值,多虧 #blackold 的提醒);而後,獲得相似這樣的 list, "" " a" "b" "" "c" 。若是此時 echo $var,則須要在這些變量之間用空格隔開,也就是"" [space] " a" [space] "b" [space] "" [space] "c" ,忽略掉空值,最終輸出是 [space][space]a[space]b[space][space]c !
若是最後一個字符不是分隔符,如 var="a:b",那麼最後一個分隔符後的變量就是最後一個變量!
這個地方要注意下!!若是IFS就是空格,那麼相似於" [space][space]a[space]b[space][space]c "會合並重復的部分,且去頭空格,去尾空格,那麼最終輸出會變成相似 a[space]b[space]c ,因此,若是IFS是默認值,那麼處理的結果就很好算出來,直接合並、忽略多餘空格便可!
另外,$* 和 $@ 在函數中的處理過程是這樣的(只考慮"原始值"!)!"$@",就是像上面處理後賦值,可是 "$*" 卻不同!它的值是用分隔符(如":")而不是空格隔開!具體例子見最後一個例子!
好了,如今來解釋 for 循環的內容。for 循環遍歷上面這個列表就能夠了,因此 for 循環的第一個輸出是空!("012"是echo輸出的換行符 )。。。。後面的依次類推!不信能夠試試下面這個例子,結果是同樣的!
3、IFS的其餘實例
Example 1:
解釋下:x 的值是 "ab::cd",當進行到 echo $x 時,由於$符,因此會進行變量替換。Shell 根據 IFS 的值將 x 分解爲 ab "" cd,而後echo,插入空隔,ab[space]""[space]cd,忽略"",輸出 ab cd 。
Example 2 :
解釋:這是 http://bbs.chinaunix.net/thread-207178-1-1.html 上的一個例子。此時IFS是默認值,本但願把全部的輸入(包括空格)都放入變量a中,可是輸出的a卻把前面的空格給忽略了!!緣由是:默認的 IFS 會按 space tab newline 來分割。這裏須要注意的一點是,read 命令的實現過程,即在讀入時已經替換了。解決辦法是在開頭加上一句 IFS=";" ,這裏必須加上雙引號,由於分號有特殊含義。
Example 3 :
解釋:何時會根據 IFS 來"處理"呢?我以爲是,對於不加引號的變量,使用時都會參考IFS,可是要注意其原始值!
Example 4 :
另一個例子,把IP地址逆轉輸出:
Example 5 :
Complex_Example 1: http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=3660898&page=1#pid21798049
輸出爲:
因爲 "output_args_ifs $var" 中 $var 沒有加引號,因此根據IFS替換!根據IFS劃分出變量: "" "" "a" "b" "" "c" "" ""(能夠經過輸出 $# 來測試參數的個數!),重組的結果爲
"$@" 的值是 "" [space] "" [space] "a" [space] "b" [space] "" [space] "c" [space] "" [space] "",能夠經過,echo==>" a b c "
"$*" 的值是 "" [IFS] "" [IFS] "a" [IFS] "b" [IFS] "" [IFS] "c" [IFS] "" [IFS] "",忽略"",echo=>"::a:b::c::"
注意, $* 和 $@ 的值都是 "" "" "a" "b" "" "c" "" "" 。能夠說是一個列表……由於他們原本就是由 $1 $2 $3……組成的。
因此,《Linux程序設計》裏推薦使用 $@,而不是$*
總結:IFS 其實仍是很麻煩的,稍有不慎就會產生很奇怪的結果,所以使用的時候要注意!我也走了很多彎路,只但願能給後來者一些幫助。本文如有問題,歡迎指正!!謝謝!