Linux命令的工作原理(1)——sed的工作原理__Linux

來源:互聯網
上載者:User

說明:本文章純屬個人觀點,不保證絕對正確,歡迎大家批評和指正,同時我自己也會對本文不斷的更新和完善。


前言

本人酷愛Linux,Linux改變了我對命令列的看法,多年前在學校用Windows批處理的時候,覺得命令列一點都不方便,討厭死了,畢業找工作的時候發現很多公司要求熟悉Linux環境,所以當時就迫不得以學Linux了,剛學的時候覺得晦澀難懂,有很多新觀念,學到Linux中一切皆檔案的時候,開始有點興趣了,用著用著,發現命令列也可以很美,用了Linux之後再用Windows的批處理,會感覺落差很大。

學Linux的方法,最初可能是看書,看部落格啊,進一步就是看man手冊啊,再一步就有可能去官網看英文版的指南,不過很多人是到網上拷貝某個用法,熟悉常用參數,而不知道這些命令的工作原理,所以本系列文章主要討論這幾個命令的工作原理,而不是用法。本文假定你已瞭解了基本用法。你會發現當你瞭解了其工作原理之後,你可以很靈活的使用它,對一個需求,你會很清楚是否可能用某命令實現。我的觀點是學東西一定要把概念搞清楚,弄清了概念,其用法就很好理解了,就不用死記硬背了。

首先補充一句,Linux的所有命令都是一個可執行檔,是一個程式,像Windows一樣,只是沒有圖形介面,啟動它是在shell裡輸入其名字,而不是雙擊它,這點初學者可能還不是清楚。

總體工作原理

sed的鼻祖是ed,sed很多命令是從ed繼承過的,雖然這玩意兒是五百年前的老古董了,但它是理解sed的一個很好的工具,先簡單介紹一下吧,ed是最初Unix一個檔案編輯器,現以被emacs和moe取代,為了相容,Linux現在的發布版一般都保留了它,它面向行的,即一次只能處理一行文本,是也是互動式,下面讓我們一起首玩玩這個老古董吧,先cat一下檔案,看下內容:

elwin@Ubuntu64:~/work$ cat file1.txt hello1hello2world1world2
我們再用ed開啟這個檔案,看看會發現什麼:
elwin@Ubuntu64:~/work$ ed file1.txt 28
只輸出了28,下面還有個游標在閃,28指的是長度,分行符號也算,你不信可以數一下,下面我輸入1p,看看會發生什麼:
1phello1
輸出了第一行,再輸入個1d試試:
1d1p    hello2
(注意1d無輸出資訊),輸入1p後,顯示的是第二行,說明第一行已刪除了。

通俗的講,sed可以理解成ed的指令碼模式,你先寫好了指令碼,sed就從輸入中一行一行的讀取,對讀入的每一行都用你的指令碼代碼處理一遍,所以,如果你有n行,那你的指令碼會被運行n次,你寫的地址,如“1p”的“1”是被正成了條件來使用,讀入每一行時,都會判斷一下行號,如果行號符號才執行相當命令。

這是最原始的sed的原理,到了後來,發現sed不能處理多行文本,於是引進了模式空間(pattern space)和暫存空間(hold space)的概念,但總體工作原理變化不大,只是讀入的每一行刪除行尾的分行符號放入模式空間,再執行所有命令,執行完所有的命令之後,再加回刪過的分行符號並列印到輸出,而暫存空間一般情況下不會用到,只有要處理多行檔案是才會用到,操作暫存區也新加了專門的命令(‘h’, ‘H’, ‘x’, ‘g’, ‘G’ )。關於工作原理官網的英文原話是這樣的:

sed maintains two data buffers: the active pattern space, and the auxiliary hold space. Both are initially empty.
sed operates by performing the following cycle on each line of input: first, sed reads one line from the input stream, removes any trailing newline, and places it in the pattern space. Then commands are executed; each command can have an address associated to it: addresses are a kind of condition code, and a command is only executed if the condition is verified before the command is to be executed.
When the end of the script is reached, unless the -n option is in use, the contents of pattern space are printed out to the output stream, adding back the trailing newline if it was removed Then the next cycle starts for the next input line.
Unless special commands (like ‘D’) are used, the pattern space is deleted between two cycles. The hold space, on the other hand, keeps its data between cycles (see commands ‘h’, ‘H’, ‘x’, ‘g’, ‘G’ to move data between both buffers).

翻譯:sed擁有兩個資料緩衝區,,一個活動的模式空間和一個輔助的暫存空間,起始時都為空白的,之後sed會對輸入的每一行執行一個這樣的迴圈,直到讀完檔案:首先讀入一行(注意:空行也是一行),刪掉結尾的換空符(如果是空行相當於刪光光了),然後對這一行一條一條的執行所有的命令,如果命令關聯了一個地址,該地址被當成條件,只有地址符號才執行命令。當指令碼裡的命令執行完後,且沒有指定-n選項,就會把模式空間的內容加上之前刪過的分行符號列印到輸出,然後讀入下行,執行下一個迴圈。如果沒有使諸如‘D’的特殊命令,那會在兩個迴圈之間清空模式空間,但不會清空暫存空間。流程圖如下:

懂了這個原理之後,你可能會發現了兩個有趣的情況:一、如果對檔案只執行p命令,那麼輸出將是每行被重複了一遍;二、如果對檔案只執行d命令,那又會如何呢,如果你想當然的把流程當成是:刪除換行-執行d刪除內容-加上換換行,那輸出結果應該是一空行,但實際輸出結果是不會輸出空行,這是因為d命令不走這個流程,它的功能是刪除模式空間,並立即開始下一個迴圈。

需要說明的時正規運算式/regexp/是用來篩選行,功能相當於行號都表示地址,還有不要搞混了/hello/p和s/hello/world/p,前一個p是sed的命令,其正規運算式是表示地址的,意思是對匹配了的行執行p命令,後一個p是s命令的flag,而正規運算式是s命令的文法,此外,s命令可以接收這兩種形式的的地址,如:

elwin@Ubuntu64:~/work$ sed '/hello/s/o/abc/' file1.txt hellabc1hellabc2world1world2
其中的/hello/表示地址,當然也可以使二點地址格式:
elwin@Ubuntu64:~/work$ sed '/hello/,/world/s/o/abc/' file1.txthellabc1hellabc2wabcrld1world2

.部分命令說明

sed可以接一個或多個指令碼(scrip),如果沒有-e選項,則把第一個非選項參數當成指令碼,可接多個,每個-e指定一個指令碼的, 一個指令碼可以包含多個命令(command),用分號或空行分隔(有的命令不能使分號分隔則必需使空行或放到最後),處理時,先用第一個-e後面的script對其進行處理,再用第二-e後面的script處理,用所有-e處理完之後。在單一個指令碼中也是一樣, 依次按順序處理. 一個命令可以是一個命令集, 用大括弧包住, 即{ commands }:  命令集按某個地址進行處理時很方便。
“a\” 起作用時機是本輪迴圈已結事,即將開始下輪迴圈時,所以是增加到下一行,而不是本行。如:

elwin@Ubuntu64:~/work$ sed 'a\1234234234' file1.txt    hello11234234234hello21234234234world11234234234world21234234234
.暫存空間說明

h命令是把模式空間內容替換寫暫存空間,g命令做相逆的操作,H和G則是追加,但都會新添加一個分行符號再追加內容,x是交換兩個空間的內容。看個例子:

elwin@Ubuntu64:~/work$ sed 'H;$G' file1.txt      hello1hello2world1world2hello1hello2world1world2
(這裡面的‘$’是代表末行),功能是把檔案複製了一遍,你還可以多複製幾篇,如:
elwin@Ubuntu64:~/work$ sed 'H;${G;G}' file1.txt      hello1hello2world1world2hello1hello2world1world2hello1hello2world1world2
為何隔了個空行呢,是因為沒G命令在先加一個分行符號,再追加內容,而在處理第一行之前,暫存空間還是空的,它也會將加入一個分行符號再追加內容,那怎麼讓他不隔個空行呢,思路是針對第一行,使用h而不使用H,於是,就變成了這樣:
elwin@Ubuntu64:~/work$ sed '1h;1!H;$G' file1.txt hello1hello2world1world2hello1hello2world1world2
(這裡的驚歎號“!”表示對於合格行不執行,即對第一行不執行H)。


參考資料:

gnu官方手冊:http://www.gnu.org/software/sed/manual/sed.html


說明:本文章純屬個人觀點,不保證絕對正確,歡迎大家批評和指正,同時我自己也會對本文不斷的更新和完善。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.