隨筆-124  評論-194  文章-0  trackbacks-0
          什么是sed?
          sed 是在 UNIX ® 操作系統(tǒng)上運(yùn)行的一個(gè)非交互式上下文編輯器。sed 被設(shè)計(jì)在下列三種情況下發(fā)揮作用:
          1) 編輯那些對舒適的交互式編輯而言太大的文件。
          2) 在編輯命令太復(fù)雜而難于在交互模式下鍵入的時(shí)候編輯任何大小的文件。
          3) 要在對輸入的一趟掃描中有效的進(jìn)行多個(gè)‘全局’編輯函數(shù)。
          因?yàn)槊看沃话演斎氲哪承┬旭v留在內(nèi)存中,并且不使用臨時(shí)文件,所以可編輯的文件的有效大小,只受限于輸入和輸出要同時(shí)共存于次級(jí)存儲(chǔ)的要求。
          可以單獨(dú)的建立復(fù)雜的編輯腳本并作為給 sed 的命令文件。對于復(fù)雜的編輯,這節(jié)省了可觀的鍵入和隨之而來的錯(cuò)誤。從命令文件運(yùn)行 sed 高效于作者所知道的任何交互式編輯器,甚至包括能用預(yù)先寫好的腳本驅(qū)動(dòng)的編輯器。

          sed是如何操作的?
          sed 缺省的把標(biāo)準(zhǔn)輸入復(fù)制到標(biāo)準(zhǔn)輸出,再把每行寫到輸出之前可能在其上進(jìn)行一個(gè)或多個(gè)編輯命令。這種行為可以通過命令行上的標(biāo)志來更改。
          sed編輯命令的一般格式為:
              [address]command [parameter]

          一個(gè)或兩個(gè)[address]是可以省略的;可以用任何數(shù)目的空白或 tab 把地址和函數(shù)分隔開。sed函數(shù)必須出現(xiàn)。依據(jù)給出的是哪個(gè)函數(shù),參數(shù)可能是必需的或是可選的。忽略在這些行開始處的 tab 字符和空格。

          sed如何對文件的行操作的步驟?
          1)sed對[address]里匹配的行,執(zhí)行命令并輸出在stdout。
          2)sed在對匹配的行的執(zhí)行完所有命令后,自動(dòng)跳到下一個(gè)匹配行重復(fù)命令執(zhí)行。
          3)sed對文本行的操作,并不會(huì)更改文本的行內(nèi)容。sed是從文本中調(diào)出行內(nèi)容,并備份,然后在這備份上執(zhí)行sed命令,最終在stdout上輸出操作后的行。


          sed命令行格式和標(biāo)志:
          sed命令格式:sed [option] 'sed-script' file
          在命令行上option:
              * -n:告訴 sed 不復(fù)制所有的行,只復(fù)制 p 函數(shù)或在 s 函數(shù)后 p 標(biāo)志所指定的行。
              * -e:告訴 sed 把下一個(gè)參數(shù)接受為編輯命令。
              * -f:告訴 sed 把下一個(gè)參數(shù)接受為文件名;這個(gè)文件應(yīng)當(dāng)包含一行一個(gè)的編輯命令。

          什么是模式空間?
          模式匹配的范圍叫做模式空間。一般而言,模式空間是輸入文本中某一行,但是可以通過使用 N 命令把多于一行讀入模式空間

          sed如何從輸入文件里選擇編輯的行?
          編輯命令要應(yīng)用于其上的,輸入文件中的行可以通過地址來選擇。地址可以是行號(hào)或者是上下文地址。

          通過用花括號(hào)(‘{ }’)組合(group)命令,可以用一個(gè)地址(或地址對)來控制一組命令的應(yīng)用。

          sed的行號(hào)是十進(jìn)制整數(shù)。在從輸入讀入每一行的時(shí)候,增加一個(gè)行號(hào)計(jì)數(shù)器;行號(hào)地址匹配(選擇)導(dǎo)致這個(gè)內(nèi)部計(jì)數(shù)器等于地址行號(hào)的輸入行。計(jì)數(shù)器在多個(gè)輸入文件上累計(jì)運(yùn)行,在打開一個(gè)新文件的時(shí)候它不被復(fù)零(reset)。

          作為特殊情況,字符 $ 匹配輸入文件的最后一行。

          上下文地址是包圍在斜杠中(‘/’)的模式(‘正則表達(dá)式’)。sed 識(shí)別的正則表達(dá)式被構(gòu)造如下:
             * 1) 普通字符(不是下面討論的某個(gè)字符)是一個(gè)正則表達(dá)式,并且匹配這個(gè)字符。
              * 2) 在正則表達(dá)式開始處的‘^’符號(hào)(circumflex)匹配在行開始處的空(null)字符。
              * 3) 在正則表達(dá)式結(jié)束處的美元符號(hào)‘$’匹配在行結(jié)束處的空字符。
              * 4) 字符‘"n’匹配內(nèi)嵌的換行字符,而不是在模式空間結(jié)束處的換行。
              * 5) 點(diǎn)‘.’匹配除了模式空間的終止換行之外的任何字符。
              * 6) 跟隨著星號(hào)‘*’的正則表達(dá)式,匹配它所跟叢的正則表達(dá)式的任何數(shù)目(包括 0)的毗連出現(xiàn)。
              * 7) 在方括號(hào)‘[ ]’內(nèi)的字符串,匹配在字符串內(nèi)的任何字符,而非其他。但是如果這個(gè)字符串的第一個(gè)字符是‘^’符號(hào),正則表達(dá)式匹配除了在這個(gè)字符串內(nèi)的字符和模式空間的終止換行之外的任何字符。
              * 8) 正則表達(dá)式的串聯(lián)(concatenation)是正則表達(dá)式,它匹配這個(gè)正則表達(dá)式的成員所匹配的字符串的串聯(lián)。
              * 9) 在順序的‘"(’和‘")’之間的正則表達(dá)式,在效果上等同于沒有它修飾的正則表達(dá)式,但它有個(gè)副作用,將在下面的 s 命令和緊后面的規(guī)定 10 中描述。
              * 10) 表達(dá)式‘"d’意味著與在同一個(gè)表達(dá)式中先前的‘"(’和‘")’中包圍的表達(dá)式所匹配的那些字符同樣的字符串。這里的 d 是一個(gè)單一的數(shù)字;指定的字符串是‘"(’的從左至右的第 d 個(gè)出現(xiàn)所起始的字符串。例如,表達(dá)式‘^"(.*")"1’匹配開始于同一個(gè)字符串的兩次重復(fù)出現(xiàn)的行。
              * 11) 孤立的空正則表達(dá)式(就是‘//’)等價(jià)于編譯的最后一個(gè)正則表達(dá)式。

          注意:要使用正則表達(dá)式的元字符(^ $ . * [ ] " /)中的某一個(gè)字符作為文字(去匹配輸入中它們自身的出現(xiàn)),要對這個(gè)特殊字符前導(dǎo)一個(gè)反斜杠‘"’。

          有的sed命令可能有 0,1 或 2 個(gè)地址。在每個(gè)命令中都給出了允許的地址的最大數(shù)目。地址多于最大允許個(gè)數(shù)的命令被認(rèn)為是錯(cuò)誤的。

          如果命令沒有地址,它應(yīng)用于輸入中每個(gè)行。
          如果命令有一個(gè)地址,它應(yīng)用于匹配這個(gè)地址的所有行。
          如果命令有兩個(gè)地址,它應(yīng)用于匹配第一個(gè)地址的第一行,和直到(并包括)匹配第二個(gè)地址的第一個(gè)后續(xù)行的所有后續(xù)行。接著在后續(xù)的行上再次嘗試匹配第一個(gè)地址,并重復(fù)這個(gè)處理。兩個(gè)地址用逗號(hào)分隔。
          例子:
              /an/         匹配我們樣例文本的第 1, 3, 4 行
              /an.*an/     匹配第 1 行
              /^an/        沒有匹配行
              /./          匹配所有行
              /"./         匹配第 5 行
              /r*an/       匹配第 1,3, 4 行(number = zero!)
              /"(an").*"1/ 匹配第 1 行


          sed的命令格式:
          [address1]command

          [address1],[address2]command

          前者表示sed對匹配地址的行進(jìn)行操作
          后者表示sed對從匹配地址1的行到匹配地址2的行之間(包括地址1和地址2行)所有的行進(jìn)行操作

          另外sed命令還可以用大括號(hào)進(jìn)行分組,使其作用于同一個(gè)地址:
          [address]{
              command1
              command2
              command3
          }


          [address]{command1;command2;command3}

          注意:sed的[address]是正則表達(dá)式,并且要用/ /限定范圍,如:
          /^$/,/^ */d

          如果sed命令之間用;分隔,可以將多個(gè)命令寫在同一行,如:n;d;s/sdfd//g

          sed腳本的注釋行第一個(gè)字符必須是"#"號(hào),如:
          #wstar.scd:xxxx

          sed的命令函數(shù):

          sed命令集由25個(gè)命令組成,而且sed的命令大多是用單個(gè)字符表示。

          n(讀取下一行)
          [address]n

          讀取[address]匹配行的下一行
          n命令改變了正常的流控制,導(dǎo)致輸入的下一行取代模式空間中的當(dāng)前行,如:
          /^".H1/{n;/^$/d}      #將匹配匹配^".H1的下一空行刪除

          =(打印行號(hào))
          [address]=

          在stdout,打印匹配的行號(hào),如:
          /   if/{
          =;p
          }

          p(打印行):
          /address/p

          在stdout,打印匹配的行

          d(刪除):
          [address]d

          如果模行匹配address,那么就刪除整個(gè)這一行
          [address1],[address2]d
          刪除匹配address1和address2中間的所有行
          注意:不允許在被刪除的行上做進(jìn)一步的操作
          例子:
          /^".sp/d
          /^&/,/^".bp/d

          a(追加新行):
          [address]a"
          text

          在匹配address的行后追加新的text行。
          注意:必須是a命令后跟一個(gè)"用于轉(zhuǎn)義第一個(gè)行尾,text必須從下一行開始。
          例子:
          /<larry's address>/a"
          4700 Cross Court"
          Freach tjck,IN

          i(插入新行):
          [address]ni"
          text

          表示在匹配address的行前插入新的text行。

          ni"
          text

          表示在第n行插入新的text行

          注意:必須是i命令后跟一個(gè)"用于轉(zhuǎn)義第一個(gè)行尾,text必須從下一行開始。
          例子:
          /<larry's address>/i"
          4700 Cross Court

          2i"
          .so macros"
          .ds CH first draft

          q(退出命令):
          [address]q

          退出命令q會(huì)使sed停止讀取新的輸入行(并停止將他們發(fā)送到輸出)
          /^".".$/q

          nq
          向stdout輸出1到(n-1)行的內(nèi)容,到第n行時(shí)退出sed
          sed '100q' test

          c(行更改):
          [address]c"
          text


          [address1],[address2]c"
          text

          注意:必須是i命令后跟一個(gè)"用于轉(zhuǎn)義第一個(gè)行尾,text必須從下一行開始
          c命令刪除當(dāng)前行并且在該位置放置所提供的文本。當(dāng)想要匹配行并整個(gè)取代它時(shí)使用c命令。
          /^".sp/c"
          .sp .5

          /^From/,/^$/{
          s/^From//p
          c"
          <Mail Header Removed>
          }

          y(轉(zhuǎn)換):
          轉(zhuǎn)換語法:y/charators/change-charactors/

          y的轉(zhuǎn)換是根據(jù)字符的位置來進(jìn)行的,//里用的不是正則表達(dá)式,只是一般的字符序列。它沒有詞的概念,只是簡單的將對應(yīng)位置上的字符作替換。
          注意:charactors和change-charactors的字符數(shù)目要一致
          y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/

          s(替換):
          替換命令語法為[address]s/pattern/replacement/flags

          修飾替換標(biāo)志flags是:
          n     1-512之間的一個(gè)數(shù)字,表示在模式空間里對匹配pattern的字符串第n次出現(xiàn)后開始進(jìn)行替換,將替換后的行輸出stdout
          g     對模式空間里匹配pattern的字符串進(jìn)行全局替換,將替換后的行輸出stdout
          p     將匹配行的內(nèi)容替換后輸出stdout
          w file 將模式空間內(nèi)容寫到文件file中
          替換命令s應(yīng)用于與[address]匹配的行。如果沒有指定行,那么就應(yīng)用于與pattern匹配的所有行。

          在repalcement里可以利用&符號(hào),表示在替換字符串中引用pattern整個(gè)匹配內(nèi)容,如:
          s/See Section [1-9][0-9]*".[1-9][0-9]*/(&)/         #給匹配的字符串添加小括號(hào)()

          sed的控制流函數(shù):
          !(非匹配)
          [address]!command   #在不匹配的行,執(zhí)行sed命令

          [address1],[address2]!command
          非命令導(dǎo)致(寫在同一行上的)下一個(gè)命令,應(yīng)用到所有的且只能是未被地址部分選擇到那些輸入行上。
          /^$/!d
          #刪除不是空行的所有行

          {(命令集)
              組合命令‘{’導(dǎo)致下一組命令作為一個(gè)塊而被應(yīng)用(或不應(yīng)用)到組合命令的地址所選擇的輸入行上。在組合控制下的的命令中的第一個(gè)命令可以出現(xiàn)在與‘{’相同的一行或下一行上。
              組合的命令由自己獨(dú)立在一行之上的相匹配的‘}’終止。
              組合可以嵌套。

          :label(標(biāo)簽)
          標(biāo)簽是任意不多于7個(gè)字符的序列。標(biāo)簽本身占據(jù)一行并以冒號(hào)開始:,如:
          :mylabel
          標(biāo)簽將被分支b和測試t命令調(diào)用,改變sed控制流。
          b mylabel
          注意不要在標(biāo)簽后插入空格

          b(分支)
          branch命令用于腳本將控制權(quán)轉(zhuǎn)移別處。

          [address]b <label>
          label是可選的,如果沒有給出label,sed對該行的控制流就會(huì)自動(dòng)轉(zhuǎn)移到結(jié)尾處。如果有l(wèi)abel就繼續(xù)執(zhí)行標(biāo)簽后的行。
          例子:
          /^".ES/,/^".EE/b
          s/^"/''/
          s/^$/''/
          ...
          s/@DQ@/"/g

          :top
          command1
          commnd2
          /pattern/b top
          command3
          #模式pattern不匹配時(shí),sed執(zhí)行command1,command2,command3
          #模式pattern匹配時(shí),控制流會(huì)跳轉(zhuǎn)到標(biāo)簽top處,sed執(zhí)行command1,command2,command1,command2,command3

          command1
          /pattern/b end
          command2
          :end
          command3
          #模式pattern不匹配時(shí),sed執(zhí)行command1,command2,command3
          #模式pattern匹配時(shí),sed執(zhí)行command1,command3

          t(測試是否成功替換)
          test命令用于判斷當(dāng)前匹配的地址上是否進(jìn)行了成功替換?成功替換sed的控制流就轉(zhuǎn)到標(biāo)簽。

          [address]t <label>
          label是可選的,如果沒有給出label,sed對該行的控制流就會(huì)自動(dòng)轉(zhuǎn)移到結(jié)尾處。如果有l(wèi)abel就繼續(xù)
          例子:
          /".Rh 0/{
          s/""(.*")"/"2,"3/g
          t break
          s/""(.*")"/"1,"2/g
          t break
          ...
          break:
          more commands
          }
          #若該行有替換,則直接跳到break標(biāo)簽處執(zhí)行下邊命令


          匹配多行:

          假設(shè)我們的目標(biāo)文件test內(nèi)容是這樣的:

          file content
          aabbcc<<<comment part 1
          comment part 2>>>
          ddeeff

          現(xiàn)在需要把<<<...>>>這一段替換為“COMMENT”,那么sed語法應(yīng)當(dāng)是:

          :begin
          /<<</,/>>>/ {
          />>>/! {
          $! {
          N;
          b begin
          }
          }
          s/<<<.*>>>/COMMENT/;
          }

          上述語句存儲(chǔ)在test.sed中,那么執(zhí)行的方式和結(jié)果就是:

          $ sed -f test.sed test
          file content
          aabbccCOMMENT
          ddeeff

          把正則直接寫到命令里面也可以,用“;”來分隔命令即可:

          $ sed -e ":begin; /<<</,/>>>/ { />>>/! { $! { N; b begin }; }; s/<<<.*>>>/COMMENT/; };" test
          file content
          aabbccCOMMENT
          ddeeff

          注意右花括號(hào)之后也要加上分號(hào)“;”,如果再加上-i參數(shù)就可以直接把改動(dòng)寫到原文件中去了。

          怎么樣?看懂了么?我來詳細(xì)說明吧,看那個(gè)多行命令的test.sed文件的內(nèi)容:

          • 首先花括號(hào){}代表命令塊的開始,類似c的語法,后面就不再說了。

          • :begin,這是一個(gè)標(biāo)號(hào),man中叫做label,也就是跳轉(zhuǎn)標(biāo)記,供b和t命令用,本例中使用了b命令。

          • /<<</,/>>>/,這是一個(gè)地址范圍(Addresses),后面 {}中的命令只對地址范圍之間的內(nèi)容使用。其中逗號(hào)前面的部分是開始地址,逗號(hào)后面是結(jié)束地址,都是正則表達(dá)式。由于sed是“流”式“行”處理,所以結(jié) 束地址是可以省略的,即如果地址的結(jié)束范圍不存在,那么將一直處理到文件結(jié)尾。本例中使用這個(gè)地址范圍主要是縮小處理的數(shù)據(jù)量,因?yàn)殡m然后面用N命令把對 一行的處理擴(kuò)展為了多行,但如果從文件開頭一直N擴(kuò)展到<<<出現(xiàn)為止,buffer中要處理的字符串可能會(huì)很長,影響效率。所以去掉 這個(gè)處理范圍也是能夠得到正確結(jié)果的,比如:

            $ sed -e ":begin; { />>>/! { $! { N; b begin }; }; s/<<<.*>>>/COMMENT/; };" test
            or
            $ sed -e "{:begin; />>>/! { $! { N; b begin }; }; s/<<<.*>>>/COMMENT/; };" test
          • />>>/!>>>是要替換內(nèi)容的結(jié)束標(biāo)記,帶上!就是說當(dāng)一行處理完畢之后,如果沒有發(fā)現(xiàn)結(jié)束標(biāo)記。。。

          • $!$在正則中表示字符串結(jié)尾,在sed中代表文件的最后一行,本句和上一句結(jié)合起來的意思就是:如果在本行沒有發(fā)現(xiàn)結(jié)束標(biāo)記,并且當(dāng)前掃描過的行并不是文件的最后一行。

          • N;,把下一行的內(nèi)容追加(append)到緩沖區(qū)(pattern)之后,在我們的例子中,在處理aabbcc<<<comment part 1這一行的內(nèi)容時(shí),就會(huì)執(zhí)行到這里,然后把下一行的內(nèi)容comment part 2>>>一起放入緩沖區(qū),相當(dāng)于“合并”成了一行(sed的緩沖區(qū)中默認(rèn)都只會(huì)包含一行的內(nèi)容)。

          • b begin,由于仍然沒有找到結(jié)束標(biāo)記<<<(注意上一條說的緩沖區(qū)還沒有被處理),所以在這里跳回到標(biāo)號(hào)begin,重新開始命令。如果開始和結(jié)束標(biāo)記之間間隔了多行,那么就會(huì)有多次跳轉(zhuǎn)發(fā)生。

          • s/<<<.*>>>/COMMENT/;,終于,/>>>/!不再匹配成功,也就是我們已經(jīng)找到了結(jié)束標(biāo)記,那么用s命令來進(jìn)行替換。如果開始和結(jié)束標(biāo)記在一行的話,就會(huì)越過上面那些復(fù)雜的處理,直接執(zhí)行到這里了。

          轉(zhuǎn)自:
          http://www.fwolf.com/blog/post/346
          http://hi.baidu.com/hellolinuxworld/blog/item/5e3aa7080e6350c63bc76309.html


          posted on 2009-09-01 10:12 我愛佳娃 閱讀(3977) 評論(1)  編輯  收藏 所屬分類: 工具使用

          評論:
          # re: SED最佳參考[未登錄] 2009-11-23 20:02 | fly
          找了很久,這篇非常好。感謝分享啊。。  回復(fù)  更多評論
            
          主站蜘蛛池模板: 宁化县| 鲁甸县| 彝良县| 信宜市| 镇雄县| 凌源市| 吴川市| 宣武区| 新田县| 子长县| 黔南| 开封县| 龙里县| 泸西县| 两当县| 普洱| 田东县| 崇阳县| 宜黄县| 侯马市| 托里县| 安陆市| 蚌埠市| 历史| 赫章县| 蓬莱市| 财经| 吉安市| 宜宾县| 玉山县| 姚安县| 土默特左旗| 饶河县| 吉隆县| 兴和县| 金寨县| 霞浦县| 茌平县| 鹰潭市| 平和县| 徐州市|