最有用系列:python
《Linux生產環境上,最經常使用的一套「vim「技巧》編程
《Linux生產環境上,最經常使用的一套「Sed「技巧》vim
《Linux生產環境上,最經常使用的一套「AWK「技巧》bash
《"Sed" 高級功能:我這小腦瓜都快繞暈了》markdown
sed命令有兩個空間,一個叫pattern space,一個叫hold space。這兩個空間可以證實人類的腦瓜容量是很是小的,須要通過大量的訓練和燒腦的理解,才能適應一些很是簡單的操做。編程語言
不信看下面簡單的命令,做用是,刪除文件中最後兩行。編輯器
sed 'N; $!P;$!D;$d' file 複製代碼
在《Linux生產環境上,最經常使用的一套「Sed「技巧》一文中,咱們介紹了經常使用的sed命令和操做,並且使用了兩張圖來做爲輔助。但惋惜的是,這兩張圖,嚴格來講是不許確的 (好比s命令,只是其中的一個子集),即便它可以幫助初學者快速入門。oop
本篇屬於sed的中級用法,常見在一些sed腳本中,在平常中應用並很少,但每每可以得到意想不到的效果。post
這要從sed的工做模式來講起。測試
按照咱們讀取一個文件的尿性,通常是持續循環讀取。好比下面的python代碼,print表明p命令。with open('file', 'r') as f: for line in f.readlines(): print(line) 複製代碼
sed命令在這之上,還緩衝了另一個東西。那就是「上一行的內容」 ,叫作hold space。而當前行,叫作patter space。用python簡單表現一下:
hold_space = "" with open('file', 'r') as f: for pattern_space in f.readlines(): print(hold_space,pattern_space) hold_space = pattern_space 複製代碼
具體過程,大致與上面的代碼相似,以上面的圖爲例。在這個例子中,hold space不參與運算,是全程無感的:
一、 讀取當前行
wtf..
到 Pattern space二、 執行命令
p
,這會打印出當前行三、 把Pattern space的內容,賦值給Hold space
四、 繼續下一行的處理,循環這個過程
但我想稍微操做一下這兩個緩衝區。這個操做就是swap,使用x表示,這也是一些文本編輯器的一向尿性。
也就是,在p以前,咱們加上了個x。表示先將這兩個緩衝區進行置換,而後再往下走。
hold_space = "" with open('file', 'r') as f: for pattern_space in f.readlines(): swap(hold_space,pattern_space) print(hold_space,pattern_space) hold_space = pattern_space 複製代碼
讓我咱們來想象一下這個過程。
一、 剛開始,hold_space的內容是空。然鵝,還沒被填充,它就被使用了,和當前行進行了置換
二、 p命令用在了置換後的緩衝區上,第一次打印出了空行,fuck
三、 繼續嘟嘟嘟,如今到了最後一行,立刻進行了置換,沒機會打印就到了hold_space中了
四、 當前行,存放的是倒數第二行的數據,最後一行見光死,就永遠沒有機會面世了
咱們固然有辦法把它搞出來,好比,我執行偶數次的交換x。
sed -n 'x;x;x;x;p' file 複製代碼
有木有一股騎着羊駝走天下的的感受?
你可能會想,我對這兩個緩衝區交換,有什麼用?接下來看這個文件。
小姐姐味道公衆號
CEO
加菲貓經理
IT Manager
系統毀滅師
Sysadmin
小哥哥味道
Developer
愛賣東西的經理
Sales Manager
風清揚
Dog
複製代碼
文件奇數行是名稱,偶數行是職位。咱們想要輸出全部Manager
的名字。就可使用下面的命令。
sed -n -e 'x;n' -e '/Manager/{x;p}' file 複製代碼
命令分爲兩個部分。
x;n
表示將偶數行保存在pattern space,那麼奇數行就保存在hold space中。
/Manager/{x;p}
命令將在pattern space上執行對Manager關鍵字的查找。若是符合條件,則再次交換p和h緩衝區,輸出奇數行對應的名字。
上面的x
和n
,就是針對這兩個緩衝區的命令。這樣的命令有不少。
這些命令,若是多了,可使用{}包圍起來,就像上面的命令同樣。這些命令的位置與咱們上一篇所說的,在同一個地方。
x 請允許我用英文裝個b:Exchange the contents of the hold and pattern spaces.
d 清空當前的pattern space,而後進入下一個循環
D 刪除pattern space的第一行(multiline pattern)
h 複製pattern space到hold space
H 追加pattern spaced到hold space
g 複製hold space到pattern space
G 追加hold space到pattern space
n 讀取下一個輸入行到pattern space
N 追加下一個輸入行到pattern space,同時將兩行看作一行,可是兩行之間依然含有\n換行符
p 打印當前的pattern space
P 打印當前的pattern space中的第一行
上次提到的推箱子游戲,就用了不少這種東西。爲了使使用者在書寫sed腳本的時候真正的"自由",sed還容許在腳本中用":"設置記號。標籤,有種相似編程語言的特性了。
q 退出sed,能夠增長執行速度
l 列出當前行,包含不可打印字符
l width 列出當前行,使用一個
width characters
結尾b label 跳到相應的標籤,分之命令。
t label if分支,從最後一行開始,條件一旦知足或者T,t命令,將致使分支到帶有標號的命令處,或者到腳本的末尾。測試命令。
T label 錯誤分支,從最後一行開始,一旦發生錯誤或者T,t命令,將致使分支到帶有標號的命令處,或者到腳本的末尾。
固然還有其餘更不經常使用的,可使用man命令查看
man sed
複製代碼
看着一行行進行處理,好像很簡單是否是?不可能的,看下面幾個簡單的命令,訓練一下生鏽的腦子。
一個流水線同樣的命令
sed -n '2{h;n;x;H;x};p' file 複製代碼
交換第2行和第3行的內容
輸出最後一行
sed 'N;D' file 複製代碼
輸出文件中最後兩行
sed '$!N; $!D' file 複製代碼
刪除文件中最後兩行
sed 'N; $!P;$!D;$d' file 複製代碼
打印偶數行的另外一種寫法
sed –n 'n;p' file 複製代碼
每隔5行加入一個空行。
sed 'n;n;n;n;G' file 複製代碼
輸出含AAA和BBB和CCC(任意順序)的段落
sed -e '/./{H; $!d;}' -e 'x;/AAA/!d; /BBB/!d; /CCC/!d' file 複製代碼
顛倒行序(使末行變首行,首行變末行)
sed -n '1!G; h; $p' file 複製代碼
這個命令有點繞,首先,
1!G
對除了第一行的其餘行進行了G操做,而後反向複製回去,到了最後一行,就直接打印Pattern Space。$
表示到了最後一行執行下面的命令,也能夠是${p}
一個帶標籤的用法
sed -e :a -e '$q;N;11,$D;ba' 複製代碼
打印最後10行。a
是標籤。語法就是單獨的行,使用:
分隔。
爲了提升你在公司的競爭力,你是能夠弄一堆sed腳本唬人(埋雷)的。和某些perl腳本同樣,即便是有相關經驗的開發着,理解起來也要下點功夫,就不要說其餘人了。
這就是sed,簡約但不簡單的命令,本文算是一箇中級入門。中級入門也有點燒腦,由於你的腦瓜裏,須要一直維護着這兩個緩衝區。又是置換,又是清空,至關於人肉狀態機。固然,怎麼把這個過程講的儘可能簡單一點,仍是浪費了做者很多腦細胞的。哪怕你點個贊,也是延緩小姐姐走向老年癡呆時間的一個途徑。有了你的支持,小姐姐也能夠想點技術以外的事情,好比噴噴bat什麼的。