<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆-314  評論-209  文章-0  trackbacks-0

    一、IFS 介紹

         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.

         Shell 的環境變量分為 set, env 兩種,其中 set 變量可以通過 export 工具導入到 env 變量中。其中,set 是顯示設置shell變量,僅在本 shell 中有效;env 是顯示設置用戶環境變量 ,僅在當前會話中有效。換句話說,set 變量里包含了 env 變量,但 set 變量不一定都是 env 變量。這兩種變量不同之處在于變量的作用域不同。顯然,env 變量的作用域要大些,它可以在 subshell 中使用。

         而 IFS 是一種 set 變量,當 shell 處理"命令替換"和"參數替換"時,shell 根據 IFS 的值,默認是 space, tab, newline 來拆解讀入的變量,然后對特殊字符進行處理,最后重新組合賦值給該變量。

    二、IFS 簡單實例

    1、查看變量 IFS 的值。

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

    直接輸出IFS是看不到的,把它轉化為二進制就可以看到了,"040"是空格,"011"是Tab,"012"是換行符"\n" 。最后一個 012 是因為 echo 默認是會換行的。

    2、$* 和 $@ 的細微差別
         從下面的例子中可以看出,如果是用冒號引起來,表示這個變量不用IFS替換!!所以可以看到這個變量的"原始值"。反之,如果不加引號,輸出時會根據IFS的值來分割后合并輸出! $* 是按照IFS中的第一個值來確定的!下面這兩個例子還有細微的差別!

    $ IFS=:; $ set x y z $ echo $* x y z $ echo "$*" x:y:z $ echo $@ x y z $ echo "$@" x y z
     上例 set 變量其實是3個參數,而下面這個例子實質是2個參數,即 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

    小結:$* 會根據 IFS 的不同來組合值,而 $@ 則會將值用" "來組合值!

    3、for 循環中的奇怪現象

    1. $ for x in $var ;do echo $x |od -b ;done  
    2. 0000000 012  
    3. 0000001  
    4. 0000000 040 141 012  
    5. 0000003  
    6. 0000000 142 012  
    7. 0000002  
    8. 0000000 012  
    9. 0000001  
    10. 0000000 143 012  
    11. 0000002  
    $ 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 循環的內容!看下面這個輸出!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" 表示冒號),但是$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輸出的換行符 )。。。。后面的依次類推!不信可以試試下面這個例子,結果是一樣的!

    $ 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

    三、IFS的其他實例

    Example 1:

     

    $ IFS=: $ var=ab::cd $ echo $var ab  cd $ echo "$var" ab::cd
    解釋下:x 的值是 "ab::cd",當進行到 echo $x 時,因為$符,所以會進行變量替換。Shell 根據 IFS 的值將 x 分解為 ab "" cd,然后echo,插入空隔,ab[space]""[space]cd,忽略"",輸出  ab  cd 。

    Example 2 :

    1. $ read a  
    2.        xy  z  
    3. $ echo $a  
    4. xy  z  
    $ read a        xy  z $ echo $a xy  z

    解釋:這是 http://bbs.chinaunix.net/thread-207178-1-1.html 上的一個例子。此時IFS是默認值,本希望把所有的輸入(包括空格)都放入變量a中,但是輸出的a卻把前面的空格給忽略了?。≡蚴牵耗J的 IFS 會按 space tab newline 來分割。這里需要注意的一點是,read 命令的實現過程,即在讀入時已經替換了。解決辦法是在開頭加上一句 IFS=";" ,這里必須加上雙引號,因為分號有特殊含義。

    Example 3 :

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

    解釋:什么時候會根據 IFS 來"處理"呢?我覺得是,對于不加引號的變量,使用時都會參考IFS,但是要注意其原始值!

    Example 4 :

    1. #!/bin/bash  
    2. IFS_old=$IFS      #將原IFS值保存,以便用完后恢復  
    3. IFS=$’\n’        #更改IFS值為$’\n’ ,注意,以回車做為分隔符,IFS必須為:$’\n’  
    4. for i in $((cat pwd.txt)) #pwd.txt 來自這個命令:cat /etc/passwd >pwd.txt  
    5. do  
    6.     echo $i  
    7. done  
    8. IFS=$IFS_old      #恢復原IFS值  
    #!/bin/bash IFS_old=$IFS      #將原IFS值保存,以便用完后恢復 IFS=$’\n’        #更改IFS值為$’\n’ ,注意,以回車做為分隔符,IFS必須為:$’\n’ for i in $((cat pwd.txt)) #pwd.txt 來自這個命令:cat /etc/passwd >pwd.txt do     echo $i done IFS=$IFS_old      #恢復原IFS值
    另外一個例子,把IP地址逆轉輸出:

    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

     

    輸出為:

    1. =::a:b::c::  # 少了最后一個冒號!看前面就知道為什么了  
    2. =  a b  c   
    3. []  
    4. []  
    5. [a]  
    6. [b]  
    7. []  
    8. [c]  
    9. []  
    =::a:b::c::  # 少了最后一個冒號!看前面就知道為什么了 =  a b  c  [] [] [a] [b] [] [c] []

    由于 "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"  ""  "" ??梢哉f是一個列表……因為他們本來就是由 $1 $2 $3……組成的。

    所以,《Linux程序設計》里推薦使用 $@,而不是$*

    總結:IFS 其實還是很麻煩的,稍有不慎就會產生很奇怪的結果,因此使用的時候要注意!我也走了不少彎路,只希望能給后來者一些幫助。本文若有問題,歡迎指正?。≈x謝!

    如有轉載,請注明blog.csdn.net/whuslei
    參考:
    http://blog.chinaunix.net/space.php?uid=20543672&do=blog&id=94358
    http://smilejay.com/2011/12/bash_ifs/#comment-51

    posted on 2016-04-01 15:00 xzc 閱讀(278) 評論(1)  編輯  收藏 所屬分類: linux/unix

    評論:
    # re: Shell中的IFS解惑 2016-04-01 15:01 | xzc
    #測試
    index_value1="a b c"
    index_value2="1 2 3"
    ifs=$IFS
    echo ":${ifs}:"
    IFS=$'\n'
    for i1 in ${index_value1}
    do
    echo ${i1}
    IFS=$ifs
    for i2 in ${index_value2}
    do
    echo ${i1} ${i2}
    done
    done  回復  更多評論
      
    主站蜘蛛池模板: 99热在线精品免费全部my| 免费永久在线观看黄网站| 亚洲日韩一区二区三区| 亚洲国产成人久久综合区| 国产精品99精品久久免费| 久久亚洲精品国产亚洲老地址| 亚洲国产天堂久久综合| 3d成人免费动漫在线观看| 国产亚洲美女精品久久久久| 亚洲va在线va天堂va888www| 成年女人男人免费视频播放| 美女被免费网站91色| 在线亚洲高清揄拍自拍一品区| 国产aⅴ无码专区亚洲av麻豆| 免费看韩国黄a片在线观看| 中文字幕免费在线看| 亚洲女子高潮不断爆白浆| 亚洲AV永久无码精品| 国产一级淫片a免费播放口之| 日韩人妻一区二区三区免费| 午夜亚洲乱码伦小说区69堂| 亚洲视频国产精品| 91麻豆精品国产自产在线观看亚洲| 日韩中文字幕精品免费一区| 中国国语毛片免费观看视频| 亚洲精品无播放器在线播放 | 国产成人免费a在线视频色戒| 国产va在线观看免费| 国产精品观看在线亚洲人成网| 亚洲精品永久www忘忧草| 国产精品亚洲mnbav网站| 免费毛片在线播放| 久久午夜夜伦鲁鲁片免费无码影视| kk4kk免费视频毛片| 亚洲欧美精品午睡沙发| 久久久无码精品亚洲日韩蜜臀浪潮| 亚洲一区二区三区国产精品| 全免费a级毛片免费看不卡| 亚洲最大免费视频网| 色欲A∨无码蜜臀AV免费播| yellow视频免费在线观看|