shell IFS分隔符

IFS分隔符

1 IFS 介紹

??Shell 腳本中有個(gè)變量叫 IFS(Internal Field Seprator) 期丰,內(nèi)部域分隔符短曾。完整定義是

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.

??Shell 的環(huán)境變量分為 set, env 兩種,其中 set 變量可以通過 export 工具導(dǎo)入到 env 變量中。

??其中,set 是顯示設(shè)置shell變量岸更,僅在本 shell 中有效潜圃;

??env 是顯示設(shè)置用戶環(huán)境變量 贩据,僅在當(dāng)前會(huì)話中有效荣病。

??換句話說,set 變量里包含了 env 變量渗柿,但 set 變量不一定都是 env 變量个盆。這兩種變量不同之處在于變量的作用域不同。顯然朵栖,env 變量的作用域要大些颊亮,它可以在 subshell 中使用。

??而 IFS 是一種 set 變量陨溅,當(dāng) shell 處理"命令替換"和"參數(shù)替換"時(shí)终惑,shell 根據(jù) IFS 的值,默認(rèn)是 space, tab, newline 來拆解讀入的變量门扇,然后對(duì)特殊字符進(jìn)行處理雹有,最后重新組合賦值給該變量。

2 IFS簡(jiǎn)單實(shí)例

2.1 查看變量 IFS 的值

$ echo $IFS
 
$ echo "$IFS" | od -b
0000000 040 011 012 012
0000004

??直接輸出IFS是看不到的臼寄,把它轉(zhuǎn)化為二進(jìn)制就可以看到了霸奕,"040"是空格,"011"是Tab吉拳,"012"是換行符"\n" 质帅。最后一個(gè) 012 是因?yàn)?echo 默認(rèn)是會(huì)換行的。

2.2 * 和@ 的細(xì)微差別

??如果是用冒號(hào)引起來留攒,表示這個(gè)變量不用IFS替換煤惩!所以可以看到這個(gè)變量的"原始值"。反之炼邀,如果不加引號(hào)魄揉,輸出時(shí)會(huì)根據(jù)IFS的值來分割后合并輸出

$ IFS=:;
$ set x y z
$ echo $*
x y z
$ echo "$*"
x:y:z
$ echo $@
x y z
$ echo "$@"
x y z

??上例 set 變量其實(shí)是3個(gè)參數(shù),而下面這個(gè)例子實(shí)質(zhì)是2個(gè)參數(shù)拭宁,即 set "x y z" 和 set x y z 是完全不同的

$ set "x" "y z"
$ echo $*
x y z
$ echo "$*"
x:y z
$ echo $@
x y z
$ echo "$@"
x y z
$ echo $* | od -b
0000000 170 040 171 040 172 012
0000006
$ echo "$*" | od -b
0000000 170 072 171 040 172 012
0000006

??$* 會(huì)根據(jù) IFS 的不同來組合值什猖,而 $@ 則會(huì)將值用" "來組合值

2.3 for 循環(huán)中IFS的奇怪現(xiàn)象

$ for x in $var ;do echo $x | od -b ;done
0000000 012
0000001
0000000 040 141 012
0000003
0000000 142 012
0000002
0000000 012
0000001
0000000 143 012
0000002

??且不解釋 for 循環(huán)的內(nèi)容!看下面這個(gè)輸出红淡!IFS 的值同上不狮! var=": a:b::c:"

$ echo $var |od -b
0000000 040 040 141 040 142 040 040 143 012
0000011
$ echo "$var" |od -b
0000000 072 040 141 072 142 072 072 143 072 012
0000012

??"$var"的值沒做替換,所以還是 ": a:b::c:" (注 "072" 表示冒號(hào))在旱,但是$var 則發(fā)生了變化摇零!注意輸出的最后一個(gè)冒號(hào)沒有了,也沒有替換為空格

??使用 $var 時(shí)是經(jīng)歷了這樣一個(gè)過程桶蝎!首先驻仅,按照這樣的規(guī)則 [變量][IFS][變量][IFS]……根據(jù)原始 var 值中所有的分割符(此處是":")劃分出變量谅畅,如果IFS的值是有多個(gè)字符組成,如IFS=":;"噪服,那么此處的[IFS]指的是IFS中的任意一個(gè)字符(* 是按第一個(gè)字符來分隔毡泻!),如 ":" 或者 ";" 粘优,后面不再對(duì)[IFS]做類似說明仇味!(注:[IFS]會(huì)有多個(gè)值,多虧 #blackold 的提醒);然后,得到類似這樣的 list疾牲, "" " a" "b" "" "c" 。如果此時(shí) echovar贩挣,則需要在這些變量之間用空格隔開,也就是"" [space] " a" [space] "b" [space] "" [space] "c" 没酣,忽略掉空值王财,最終輸出是 [space][space]a[space]b[space][space]c !

??如果最后一個(gè)字符不是分隔符裕便,如 var="a:b"搪搏,那么最后一個(gè)分隔符后的變量就是最后一個(gè)變量!

??如果IFS就是空格闪金,那么類似于" [space][space]a[space]b[space][space]c "會(huì)合并重復(fù)的部分疯溺,且去頭空格,去尾空格哎垦,那么最終輸出會(huì)變成類似 a[space]b[space]c 囱嫩,所以,如果IFS是默認(rèn)值漏设,那么處理的結(jié)果就很好算出來墨闲,直接合并、忽略多余空格即可郑口!

??$* 和 $@ 在函數(shù)中的處理過程是這樣的(只考慮"原始值"鸳碧!)!"$@"犬性,就是像上面處理后賦值瞻离,但是 "$*" 卻不一樣!它的值是用分隔符(如":")而不是空格隔開乒裆!具體例子見最后一個(gè)例子套利!

??現(xiàn)在來解釋 for 循環(huán)的內(nèi)容。for 循環(huán)遍歷上面這個(gè)列表就可以了,所以 for 循環(huán)的第一個(gè)輸出是空肉迫!("012"是echo輸出的換行符 )验辞。。喊衫。跌造。后面的依次類推!

??下面這個(gè)例子族购,結(jié)果是一樣

$ for x in "" " a" "b" "" "c" ;do echo $x |od -b ;done
0000000 012
0000001
0000000 040 141 012
0000003
0000000 012
0000001
0000000 142 012
0000002
0000000 012
0000001
0000000 143 012
0000002

3 IFS的其他實(shí)例

3.1 Example 1:

$ IFS=:
$ var=ab::cd
$ echo $var
ab  cd
$ echo "$var"
ab::cd

??解釋:x 的值是 "ab::cd"壳贪,當(dāng)進(jìn)行到 echo $x 時(shí),因?yàn)?符联四,所以會(huì)進(jìn)行變量替換撑碴。Shell 根據(jù) IFS 的值將 x 分解為 ab "" cd撑教,然后echo朝墩,插入空隔,ab[space]""[space]cd伟姐,忽略""收苏,輸出 ab cd 。

3.2 Example 2 :

$ read a
       xy  z
$ echo $a
xy  z

??解釋:這是 http://bbs.chinaunix.net/thread-207178-1-1.html 上的一個(gè)例子愤兵。此時(shí)IFS是默認(rèn)值鹿霸,本希望把所有的輸入(包括空格)都放入變量a中,但是輸出的a卻把前面的空格給忽略了秆乳!

??原因是:默認(rèn)的 IFS 會(huì)按 space tab newline 來分割懦鼠。這里需要注意的一點(diǎn)是,read 命令的實(shí)現(xiàn)過程屹堰,即在讀入時(shí)已經(jīng)替換了肛冶。解決辦法是在開頭加上一句 IFS=";" ,這里必須加上雙引號(hào)扯键,因?yàn)榉痔?hào)有特殊含義睦袖。

3.3 Example 3 :

$ tmp="   xy z"
$ a=$tmp
$ echo $a
$ echo "$a"

??解釋:什么時(shí)候會(huì)根據(jù) IFS 來"處理"呢?我覺得是荣刑,對(duì)于不加引號(hào)的變量馅笙,使用時(shí)都會(huì)參考IFS,但是要注意其原始值厉亏!

3.4 Example 4 :

#!/bin/bash
IFS_old=$IFS      #將原IFS值保存董习,以便用完后恢復(fù)
IFS=$’\n’        #更改IFS值為$’\n’ ,注意爱只,以回車做為分隔符阱飘,IFS必須為:$’\n’
for i in $((cat pwd.txt)) #pwd.txt 來自這個(gè)命令:cat /etc/passwd >pwd.txt
do
    echo $i
done
IFS=$IFS_old      #恢復(fù)原IFS值

??另外一個(gè)例子,把IP地址逆轉(zhuǎn)輸出:

3.5 Example 5 :

#!/bin/bash
IP=220.112.253.111
IFS="."
TMPIP=$(echo $IP)
IFS=" " # space
echo $TMPIP
for x in $TMPIP ;do 
    Xip="${x}.$Xip"
done
echo ${Xip%.}

Complex_Example 1: http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=3660898&page=1#pid21798049

function output_args_ifs(){
    echo "=$*"
    echo "="$*
    for m in $* ;do 
        echo "[$m]"
    done
}
 
IFS=':'
var='::a:b::c:::'
output_args_ifs $var

??輸出為:

=::a:b::c::  # 少了最后一個(gè)冒號(hào)!看前面就知道為什么了
=  a b  c 
[]
[]
[a]
[b]
[]
[c]
[]

??由于 "output_args_ifs var" 中var 沒有加引號(hào)沥匈,所以根據(jù)IFS替換蔗喂!根據(jù)IFS劃分出變量: "" "" "a" "b" "" "c" "" ""(可以通過輸出 $# 來測(cè)試參數(shù)的個(gè)數(shù)!)高帖,重組的結(jié)果為

?? "$@" 的值是 "" [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" "" "" 预麸〉山可以說是一個(gè)列表……因?yàn)樗麄儽緛砭褪怯?12 $3……組成的。

??所以吏祸,《Linux程序設(shè)計(jì)》里推薦使用 @对蒲,而不是*

??參考文獻(xiàn):Shell中的IFS解惑

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市贡翘,隨后出現(xiàn)的幾起案子蹈矮,更是在濱河造成了極大的恐慌,老刑警劉巖鸣驱,帶你破解...
    沈念sama閱讀 222,464評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件泛鸟,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡踊东,警方通過查閱死者的電腦和手機(jī)北滥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,033評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來闸翅,“玉大人再芋,你說我怎么就攤上這事《衅ⅲ” “怎么了祝闻?”我有些...
    開封第一講書人閱讀 169,078評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)遗菠。 經(jīng)常有香客問我联喘,道長(zhǎng),這世上最難降的妖魔是什么辙纬? 我笑而不...
    開封第一講書人閱讀 59,979評(píng)論 1 299
  • 正文 為了忘掉前任豁遭,我火速辦了婚禮,結(jié)果婚禮上贺拣,老公的妹妹穿的比我還像新娘蓖谢。我一直安慰自己捂蕴,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,001評(píng)論 6 398
  • 文/花漫 我一把揭開白布闪幽。 她就那樣靜靜地躺著啥辨,像睡著了一般。 火紅的嫁衣襯著肌膚如雪盯腌。 梳的紋絲不亂的頭發(fā)上溉知,一...
    開封第一講書人閱讀 52,584評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音腕够,去河邊找鬼级乍。 笑死,一個(gè)胖子當(dāng)著我的面吹牛帚湘,可吹牛的內(nèi)容都是我干的玫荣。 我是一名探鬼主播,決...
    沈念sama閱讀 41,085評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼大诸,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼捅厂!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起底挫,我...
    開封第一講書人閱讀 40,023評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤恒傻,失蹤者是張志新(化名)和其女友劉穎脸侥,沒想到半個(gè)月后建邓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,555評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡睁枕,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,626評(píng)論 3 342
  • 正文 我和宋清朗相戀三年官边,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片外遇。...
    茶點(diǎn)故事閱讀 40,769評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡注簿,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出跳仿,到底是詐尸還是另有隱情诡渴,我是刑警寧澤,帶...
    沈念sama閱讀 36,439評(píng)論 5 351
  • 正文 年R本政府宣布菲语,位于F島的核電站妄辩,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏山上。R本人自食惡果不足惜眼耀,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,115評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望佩憾。 院中可真熱鬧哮伟,春花似錦干花、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,601評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至鬼廓,卻和暖如春修赞,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背桑阶。 一陣腳步聲響...
    開封第一講書人閱讀 33,702評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工柏副, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蚣录。 一個(gè)月前我還...
    沈念sama閱讀 49,191評(píng)論 3 378
  • 正文 我出身青樓割择,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親萎河。 傳聞我的和親對(duì)象是個(gè)殘疾皇子荔泳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,781評(píng)論 2 361