文章出處

第十二節 linux三劍客之sed命令精講

標簽(空格分隔): Linux實戰教學筆記-陳思齊

---更多資料點我查看

1,前言

  • 我們都知道,在Linux中一切皆文件,比如配置文件,日志文件,啟動文件等等。如果我們相對這些文件進行一些編輯查詢等操作時,我們可能會想到一些vi,vim,cat,more等命令。但是這些命令效率不高,這就好比一塊空地準備搭建房子,請了10個師傅拿著鐵鍬挖地基,花了一個月的時間才挖完,而另外一塊空地則請了個挖土機,三下五除二就搞定了,這就是效率。而在linux中的“挖土機”有三種型號:頂配awk,中配sed,標配grep。使用這些工具,我們能夠在達到同樣效果的前提下節省大量的重復性工作,提高效率。
  • 接下來我們就看一下sed的詳細說明
  • sed 是Stream Editor(字符流編輯器)的縮寫,簡稱流編輯器。什么是流?大家可以想象以下流水線,sed就像一個車間一樣,文件中的每行字符都是原料,運到sed車間,然后經過一系列的加工處理,最后從流水線下來就變成貨物了。

屏幕快照 2017-02-06 下午2.08.58.png-261.1kB

  • 當然上圖中的文件內容可以是來自文件,也可以直接來自鍵盤或者管道等標準輸入,最后的結果默認情況下是顯示到終端的屏幕上,但是也可以輸出到文件中。
  • 以前工廠中沒有流水線時,生產一件商品需要十幾個工種互相配合,這樣下來利潤太低,后來就有了流水線,生產一件商品雖然還是有十幾道工序,但都是機器化生產,工人只是輔助作用,這樣利潤就大大提高了,產量也大大提高了。
  • 編輯文件也是這樣,以前我們修改一個配置文件,需要移動光標到某一行,然后添加點文字,然后又移動光標到另一行,注釋點東西.......可能修改一個配置文件下來需要花費數十分鐘,還有可能改錯了配置文件,又得返工。這還是一個配置文件,如果數十個數百個呢?因此當你學會了sed命令,你會發現利用它處理文件中的一系列修改是很有用的。只要想到在大約100多個文件中,處理20個不同的編輯操作可以在幾分鐘之內完成,你就會知道sed的強大了。

2,軟件功能與版本

  • Sed命令是操作,過濾和轉換文本內容的強大工具。常用功能有增刪改查(增加,刪除,修改,查詢),其中查詢的功能中最常用的2大功能是過濾(過濾指定字符串),取行(取出指定行)。
  • 我們現在準備學習的sed版本是GNU開源版本的,我的實驗環境是CentOS6.8系統,內核版本是2.6.32-642.el6.x86_64
[root@chensiqi1 ~]# cat /etc/redhat-release 
CentOS release 6.8 (Final)
[root@chensiqi1 ~]# uname -r
2.6.32-642.el6.x86_64
[root@chensiqi1 ~]# sed --version   # 查看sed軟件版本
GNU sed version 4.2.1

3,語法格式

sed [options] [sed -commands][input -file]
sed [選項]  【sed命令】 【輸入文件】

說明:
1,注意sed軟件以及后面選項,sed命令和輸入文件,每個元素之間都至少有一個空格。
2,為了避免混淆,本文稱呼sed為sed軟件。sed -commands(sed命令)是sed軟件內置的一些命令選項,為了和前面的options(選項)區分,故稱為sed命令
3,sed -commands 既可以是單個sed命令,也可以是多個sed命令組合。
4,input -file (輸入文件)是可選項,sed還能夠從標準輸入如管道獲取輸入。

4,命令執行流程

概括流程

Sed軟件從文件或管道中讀取一行,處理一行,輸出一行;再讀取一行,再處理一行,再輸出一行....

小知識:

一次一行的設計使得sed軟件性能很高,sed在讀取非常龐大的文件時不會出現卡頓的想象。大家都用過vi命令,用vi命令打開幾十M或更大的文件,會發現有卡頓現象,這是因為vi命令打開文件是一次性將文件加載到內存,然后再打開,因此卡頓的時間長短就取決于從磁盤到內存的讀取速度了。而且如果文件過大的話還會造成內存溢出現象。Sed軟件就很好的避免了這種情況,打開速度非常快,執行速度也很快。

詳細流程:

現有一個文件person.txt,共有五行文本,sed命令讀入文件person.txt的第一行“101,chensiqi,CEO”,并將這行文本存入模式空間(sed軟件在內存中的一個臨時緩存,用于存放讀取到的內容,比喻為工廠流水線的傳送帶。)

文件person.txt在模式空間的完整處理流程

1,判斷第1行是否是需要處理的行,如果不是要處理的行就重新從文件讀取下一行,如果是要處理的行,則接著往下走。
2,對模式空間的內容執行sed命令,比如a(追加),i(插入),s(替換)...
3,將模式空間中經過sed命令處理后的內容輸出到屏幕上,然后清空模式空間
4,讀取下一行文本,然后重新執行上面的流程,直到文件結束

上面的流程概括如下圖所示
屏幕快照 2017-02-06 下午8.56.53.png-438kB

Sed軟件有兩個內置的存儲空間:

  • 模式空間(pattern space):是sed軟件從文本讀取一行文本然后存入的緩沖區(這個緩沖區是在內存中的),然后使用sed命令操作模式空間的內容。
  • 保持空間(hold space):是sed軟件另外一個緩沖區,用來存放臨時數據,也是在內存中,但是模式空間和保持空間的用途是不一樣的。Sed可以交換保持空間和模式空間的數據,但是不能在保持空間上執行普通的sed命令,也就是說我們可以在保持空間存儲數據。

5,選項說明

option[選項] 解釋說明(帶*的為重點)
-n 取消默認的sed軟件的輸出,常與sed命令的p連用。*
-e 一行命令語句可以執行多條sed命令
-f 選項后面可以接sed腳本的文件名
-r 使用擴展正則表達式,默認情況sed只識別基本正則表達式*
-i 直接修改文件內容,而不是輸出到終端,如果不使用-i選項sed軟件只是修改在內存中的數據,并不會影響磁盤上的文件*
sed -commands[sed命令] 解釋說明(帶*的為重點)
a 追加,在指定行后添加一行或多行文本*
c 取代指定的行
d 刪除指定的行*
D 刪除模式空間的部分內容,直到遇到換行符\n結束操作,與多行模式相關
i 插入,在指定行前添加一行或多行文本*
h 把模式空間的內容復制到保持空間
H 把模式空間的內容追加到保持空間
g 把保持空間的內容復制到模式空間
G 把保持空間的內容追加到模式空間
x 交換模式空間和保持空間的內容
l 打印不可見的字符
n 清空模式空間的內容并讀入下一行
N 不清空模式空間,并讀取下一行數據并追加到模式空間*
p 打印模式空間內容,通常p會與選項-n一起使用*
P(大寫) 打印模式空間的內容,直到遇到換行符\n結束操作
q 退出Sed
r 從指定文件讀取數據
s 取代,s#old#new#g==>這里g是s命令的替代標志,注意和g命令區分。*
w 另存,把模式空間的內容保存到文件中
y 根據對應位置轉換字符
:label 定義一個標簽
b label 執行該標簽后面的命令
t 如果前面的命令執行成功,那么就跳轉到t指定的標簽處,繼續往下執行后續命令。否則,仍然繼續正常的執行流程
特殊符號 解釋說明(帶*的為重點)
對指定行以外的所有行應用命令*
= 打印當前行行號
“First~step”表示從First行開始,以步長Step遞增
& 代表被替換的內容
實現一行命令語句可以執行多條sed命令*
{} 對單個地址或地址范圍執行批量操作
+ 地址范圍中用到的符號,做加法運算

6,使用范例

6.1 統一實驗文本

為了更好的測試sed命令的用法,我們需要準備好下面的測試文件。

[root@chensiqi1 ~]# cat >person.txt<<KOF
> 101,chensiqi,CEO
> 102,zhangyang,CTO
> 103,Alex,COO
> 104,yy,CFO
> 105,feixue,CIO
> KOF          #KOF必須成對出現,表示終止輸入
命令說明:使用一條cat命令創建多行文本,文件包含上面的內容,后面的操作都會使用這個文件。

6.2 常用功能-增刪改查

接下來我們就開始學習sed命令的“四斧頭”-->增,刪,改,查。大家也不要著急,我們一個一個的學過去,熱豆腐要慢慢的吃。

6.2.1 增

  • 接下來我來教大家第一式招法-->往文件指定位置追加或插入指定文本。
  • 這個功能非常有用,比如我們平時往配置文件寫入幾行文本,最常用的是vi或vim命令,但是這2個命令是一種交互式的命令,還需要我們在vi/vim編輯器界面輸入字符串然后保存退出,操作有些繁瑣但是還能用。但是當我們學會了Shell腳本后,我們就會發現在腳本中不能正常使用vi或vim命令,為什么呢?同學們請自行體驗。
  • 我們學習Shell腳本主要是為了解放我們的雙手,執行一個腳本,然后自動往文件中寫入數據,不需要我們再動手。因此我們想到了sed軟件,它能夠幫助我們實現目的。
  • 這里我們需要用到2個sed命令,分別是:
    “a”:追加文本到指定行后,記憶方法:a的全拼是apend,意思是追加。
    “i“:插入文本到指定行前,記憶方法:i的全拼是insert,意思是插入。
6.2.1.1 單行增

首先我們看一下單行增加的用法,說白了就是在文件中增加一行文本,我們以前學過echo命令可以在文件的末尾追加文本,比較簡單,但是我們還有其他的復雜需求,比如在第10行插入一行數字等等,這里就需要sed出馬了。我們來看一下下面的例子,同學也跟著例子一起練習,命令只有多練才會熟悉,光看永遠是學不會的。

[root@chensiqi1 ~]# sed '2a 106,dandan,CSO' person.txt
101,chensiqi,CEO
102,zhangyang,CTO
106,dandan,CSO   #這就是新增那句
103,Alex,COO
104,yy,CFO
105,feixue,CIO

命令行詳解:

首先我們看一下命令的結果,我們可以看到原來的第二行“102,zhangyang,CTO” 前面插入了新的一行為“106,dandan,CSO”,原來的第2行變成第3行了。
接下來我們解讀一下sed語句的結構,sed打頭,然后接上空格(空格個數不限,但至少要有一個!)在空格后面,我們先敲上一對單引號(“)然后退格在單引號中協商‘106,dandan,CSO’。

  • 2代表指定對第2行操作,其他的行忽略
  • i代表插入的意思,2i即在第2行前插入文本
  • 2i后面加上空格,然后跟上你想要插入的文本即可

屏幕快照 2017-02-07 下午12.24.07.png-224kB
最后接上你想要處理的文件person.txt

6.2.1.2 引號的區別總結

在教學過程中,有同學問我在sed中到底使用單引號還是雙引號?這里給大家詳細說說引號的區別。

  1. 雙引號:把雙引號的內容輸出出來;如果內容中有命令,變量等,會先把命令,變量解析出結果,然后再輸出最終內容來。雙引號內命令或變量的寫法為`命令或變量`或$(命令或變量)
  2. 單引號:所見即所得,將單引號內的內容原樣輸出,阻止所有字符的轉義
  3. 不加引號:不會將含有空格的字符串視為一個整體輸出,如果內容中有命令,變量等,會先把命令,變量解析出結果,然后再輸出最終內容來,如果字符串含有空格等特殊字符,則不能完整輸出,則需改加雙引號。
  4. 倒引號(反引號Esc鍵下方):進行命令的替換,在倒引號內部的shell命令將會被執行,其結果輸出代替用倒引號括起來的文本。

Sed為何用單引號?

[root@chensiqi1 ~]# cat person.txt 
101,chensiqi,CEO
102,zhangyang,CTO
103,Alex,COO
104,yy,CFO
105,feixue,CIO
[root@chensiqi1 ~]# sed '2i $PATH' person.txt  #單引號--文本內容原封不動插入
101,chensiqi,CEO
$PATH
102,zhangyang,CTO
103,Alex,COO
104,yy,CFO
105,feixue,CIO
[root@chensiqi1 ~]# sed 2i $PATH person.txt   #不加引號,linux無法辨認空格,不會把有空格的命令當成一條命令來執行
sed: -e expression #1, char 2: expected \ after `a', `c' or `i'
[root@chensiqi1 ~]# sed "2i $PATH" person.txt #雙引號--變量$PATH被解析以后在當作文本進行插入
101,chensiqi,CEO
/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
102,zhangyang,CTO
103,Alex,COO
104,yy,CFO
105,feixue,CIO

結論一:

  • 如果引號里面是普通字符串的話,你可以任意使用單引號或者雙引號:
  • 如果引號里面是變量或者帶反引號的命令的話,你想要變量解析的結果或者命令執行的結果,那就使用雙引號;你想要引號內的原樣字符串,那就使用單引號。
  • 只要大家理解上面的用法,明白自己想要什么,那么你想用什么引號就用什么引號。
  • 其實就二選一,非此即彼,這個不行就試試那個。

結論二:

  1. 很多時候,總結的結論未必適合所有情況。但是,總結小結論,便于我們學習知識和對知識的深刻理解,因此推薦大家多做總結。
  2. 不要太糾結于結論,結論畢竟不是真理,只是我們學習過程的產物。就像數學里的平行線一樣,在初中定義就是不相交的兩條直線就是平行線,到了高中結論就是錯的了。
6.2.1.3 多行增

前面學習的內容已經實現了往文件追加或插入單行文本,但是還有插入多行文本的需求,我們也學習過cat命令能夠往文件中追加多行文本。

示例準備,請執行如下完整命令生成test.txt文件內容:

[root@chensiqi1 ~]# cat > test.txt <<EOF
> welcome to my blog.http://www.cnblogs.com/chensiqiqi/
> 
> if you like my blog\'s contents,pls support me.
> 
> 
> 
> bye!boys and girls.
> EOF
命令說明:以上就是cat的生產環境常用的生成或為文件追加內容的方法,請不要忽略上文中的空行。另外,如果內容中有單引號,$符號等特殊符號作為內容時要用“\”轉義。

以上命令執行過程及結果:

[root@chensiqi1 ~]# cat > test.txt <<EOF

> welcome to my blog.http://www.cnblogs.com/chensiqiqi/
> #此行是空行
> if you like my blog\'s contents,pls support me.
> #此行是空行
> #此行是空行
> #此行是空行
> bye!boys and girls.
> EOF #-->這里要敲回車才能結束,另外,EOF必須成對出現,但也可以用別的成對標簽替換,例如:chensiqi字符標簽。
命令說明:上面命令結果最左側的“>”是Linux系統自動生成的,不是我們手動敲的。
  • ok,我們前面已經簡單的回顧了cat命令的用法,如果大家想詳細了解cat命令的詳細用法,請持續關注我的博客。
  • 前面我們實現了用cat命令往文件中追加多行文本,但是cat命令和echo命令有同樣的缺點,只能是往文末添加內容,并不能夠在指定行操作,因此還是需要我們的sed命令出馬。
  • 首先我們需要了解一個特殊符號“\n”,這個符號叫做換行符,顧名思義換行。我們看幾個例子來認識一下這個符號。
[root@chensiqi1 ~]# echo "chensiqi";echo "chensiqi"
chensiqi
chensiqi

命令說明:上面的命令用分號“;”連接了兩條命令,然后輸出結果為2行chensiqi,但是有沒有更簡單的方法呢?
[root@chensiqi1 ~]# echo -e "chensiqi\nchensiqi"
chensiqi
chensiqi
命令說明:這里就“\n”派上用場了,行與行之間是以“\n”作為分隔符的,所以“chensiqi\nchensiqi”就等效于2行chensiqi。接下來我們用echo命令實驗一下,其中-e參數表示字符串中如果出現以下特殊字符(\n代表換行,\t代表Tab鍵等),則加以特殊處理,而不會將它當成一般文字輸出。如果大家想詳細了解echo命令的詳細用法,請持續關注我的博客。

學習完換行符,我們來看一下sed命令如何使用

[root@chensiqi1 ~]# sed '2a 106,dandan,CSO\n107,bingbing,CCO' person.txt 
101,chensiqi,CEO
102,zhangyang,CTO
106,dandan,CSO  #同時追加多行
107,bingbing,CCO  #同時追加多行
103,Alex,COO
104,yy,CFO
105,feixue,CIO
EOF

命令行分析:

  • 我們首先粗略掃一眼這個命令語句,可以發現命令結構是和單行增加文本是幾乎沒有區別的。
  • 然后我們看一下命令的結果,我們可以看到原來的第二行“102,zhangyang,CTO”后面追加了2行文本“106,dandan,CSO”和“107,bingbing,CCO”。
  • 接下來我們解讀一下sed語句的結構,sed軟件打頭,然后接上空格,在空格后面,我們先敲上一對單引號(“),然后退一格在單引號中寫上‘2a 106,dandan,CSO\n107,bingbing,CCO’。
  1. 2代表指定對第2行操作,其他的行忽略;
  2. a代表追加的意思,2a即在第2行后追加文本;
  3. 2a后面加上空格,然后跟上你想要插入的多行文本即可。這里的每行文本使用“\n”連接就可以寫成一行了。

屏幕快照 2017-02-07 下午9.24.53.png-289.3kB
最后接上你想要處理的文件person.txt

當然還有另外一種方法添加多行文本,但這種方法并沒有“\n”方便,所以在這里就簡單說一下。這種方法利用了“”,它也有換行的意思。如果大家在執行一行很長的命令時候,如果都寫在一行,那太難看了也難以理解,因此就利用到了這個符號可以將一條完整的命令分成多行,舉個例子:

[root@chensiqi1 ~]# echo chensiqi
chensiqi
[root@chensiqi1 ~]# echo \
> chensiqi
chensiqi
[root@chensiqi1 ~]# echo \ 
> chensiqi \
> is \
> me
chensiqi is me

命令說明:一條命令可以通過\符號進行多行輸出

接著說一下sed命令使用反斜線,首先輸入完“sed '2a 106,dandan,CSO ”,然后敲回車鍵,這樣窗口會顯示一個符號“>”,我們在這個符號后面接著寫命令的剩余部分“107,bingbing,CCO‘ person.txt”。

[root@chensiqi1 ~]# sed '2a 106,dandan,CSO \ 
> 107,bingibng,CCO' \  
> person.txt 
101,chensiqi,CEO
102,zhangyang,CTO
106,dandan,CSO 
107,bingibng,CCO
103,Alex,COO
104,yy,CFO
105,feixue,CIO
EOF
命令說明:結果和第一種方法是一樣的,但是我們也發現這種方法比較麻煩,因此建議大家使用第一種方法。
  • sed軟件使用命令i插入多行文本和命令和a的用法是一樣的,因此這里不再詳細列出,大家可以練習一下,就是把前面命令的“a”換成“i”。
  • 學習了這么多內容,總要有用武之地,因此大家不要看答案先獨自完成下面的企業案例!

企業案例1:優化SSH配置(一鍵完成增加若干參數

在我們學習CentOS6系統優化時,有一個優化點:更改ssh服務遠程登錄的配置。主要的操作是在ssh的配置文件/etc/ssh/sshd_config加入下面5行文本。(下面參數的具體含義見其他課程。)

Port 52113
PermitRootLogin no
PermitEmptyPasswords no
UseDNS no
GSSAPIAuthentication no

當然我們可以使用vi/vim命令編輯這個文本,但是這樣就比較麻煩,現在想用一條命令增加5行文本到第13行前?
注意:修改前別忘了備份配置文件:cp /etc/ssh/sshd_config{,.bak}
上面的命令知識要是不懂請看通配符章節

這道企業面試題可以用我們學過的sed命令多行追加功能就可以搞定。

[root@chensiqi1 ~]# sed -i '13i Port 52113\nPermitRootLogin no\nPermitEmptyPasswords no\nUseDNS no\nGSSAPIAuthentication no' /etc/ssh/sshd_config

命令說明:題目要求在第13行前插入,那就需要使用命令13i。有同學做個題目時,是這樣想的,在13行前,那不就是12行后嗎,12a也是可以的。是的,這樣也是沒錯的,這可以算是第二種方法。
最后插入的5行內容使用“\n”就可以變成一行了。
上面還有一個沒講過的選項"-i",這個選項能夠實際的修改文件內容,大家練習時可以去掉,防止改掉了配置文件。如果使用了-i,可以用備份文件還原。當然,在生產環境修改配置文件那就需要用-i選項了。
[root@chensiqi1 ~]# sed -n '13,17p' /etc/ssh/sshd_config
Port 52113
PermitRootLogin no
PermitEmptyPasswords no
UseDNS no
GSSAPIAuthentication no

命令說明:查看增加的文本內容,選項-n與命令p的具體用法見后文的6.2.4查。

6.2.2 刪

  • 前面給大家演示了第一招,是不是很好用。如果沒看懂,請再看一遍。如果學會了,那就跟著我來學習第2招--->刪除指定行文本。
  • 這個功能也是非常得有用,比如我們想刪除文件中的某些行,以前最常用的是vi或vim命令,但現在我們知道了sed命令,就應該使用這個高逼格的命令完成任務了。
  • 這里我們需要用到1個sed命令;
  • “d”:刪除文本,記憶方法:d的全拼是delete,意思是刪除。
  • 因為刪除功能比較簡單,因此我們結合地址范圍一起說明。我們前面學過sed命令可以對一行文本為目標進行處理(在單行前后增加一行或多行文本),接下來我們看一下如何對多行文本為目標操作。
6.2.2.1指定執行的地址范圍

sed軟件可以對單行或多行文本進行處理。如果在sed命令前面不指定地址范圍,那么默認會匹配所有行。
用法:n1[,n2]{sed -commands}
地址用逗號分隔開,n1,n2可以用數字,正則表達式,或者二者的組合表示。

地址范圍 含義
10{sed-commands} 對第10行操作
10,20{sed-commands} 對10到20行操作,包括第10,20行
10,+20{sed-commands} 對10到30(10+20)行操作,包括第10,30行
1~2{sed-commands} 對1,3,5,7.....行操作
10,${sed-commands} 對10到最后一行($代表最后一行)操作,包括第10行
/chensiqi/{sed-commands} 對匹配chensiqi的行操作
/chensiqi/,/Alex/{sed-commands} 對匹配chensiqi的行到匹配Alex的行操作
/chensiqi/,${sed-commands} 對匹配chensiqi的行到最后一行操作
/chensiqi/,10{sed-commands} 對匹配chensiqi的行到第10行操作,注意:如果前10行沒有匹配到chensiqi,sed軟件會顯示10行以后的匹配chensiqi的行
1,/Alex/{sed-commands} 對第1行到匹配Alex的行操作
/chensiqi/,+2{sed-commands} 對匹配chensiqi的行到其后的2行操作

下面用具體的例子演示一下,測試文件還是person.txt

[root@chensiqi1 ~]# sed 'd' person.txt 
[root@chensiqi1 ~]# 

命令說明:如果在sed命令前面不指定地址范圍,那么默認會匹配所有行,然后使用d命令刪除功能就會刪除這個文件的所有內容

屏幕快照 2017-02-07 下午11.14.04.png-102.1kB

[root@chensiqi1 ~]# sed '2d' person.txt 
101,chensiqi,CEO
103,Alex,COO
104,yy,CFO
105,feixue,CIO

命令說明:這個單行刪除想必大家能理解,指定刪除第2行的文本102,zhangyang,CTO

屏幕快照 2017-02-07 下午11.18.38.png-87.7kB

[root@chensiqi1 ~]# sed '2,5d' person.txt 
101,chensiqi,CEO

命令說明:‘2,5d’指定刪除第2行到第5行的內容,d代表刪除操作。

屏幕快照 2017-02-07 下午11.21.26.png-94.1kB

ok,上面我們實驗完了數字地址范圍,接下來我們實驗一下正則表達式的地址范圍,雖然說可以使用正則表達式,但是我們還是習慣寫出完整的匹配字符串,達到精確匹配的目的。

[root@chensiqi1 ~]# sed '/zhangyang/d' person.txt 
101,chensiqi,CEO
103,Alex,COO
104,yy,CFO
105,feixue,CIO

命令說明:
    在sed軟件中,使用正則的格式和awk一樣,使用2個”/“包含指定的正則表達式,即“/正則表達式/”。

屏幕快照 2017-02-07 下午11.27.56.png-99.4kB

當然也可以使用兩個正則表達式,如下例所示。

[root@chensiqi1 ~]# sed '/chensiqi/,/Alex/d' person.txt 
104,yy,CFO
105,feixue,CIO

命令說明:這是正則表達式形式的多行刪除,也是以逗號分隔2個地址,最后結果是刪除包含“chensiqi”的行到包含“Alex”的行

屏幕快照 2017-02-07 下午11.33.51.png-109kB

[root@chensiqi1 ~]# sed '3,$d' person.txt 
101,chensiqi,CEO
102,zhangyang,CTO

命令說明:學過正則表達式后我們知道“$”代表行尾,但是在sed中就有一些變化了,“$”在sed中代表文件的最后一行。因此本例子的含義是刪除第3行到最后一行的文本,包含第3行和最后一行,因此剩下第1,2行的內容。

屏幕快照 2017-02-07 下午11.41.31.png-99.7kB

接下來我們看一些特殊情況。

[root@chensiqi1 ~]# sed '/chensiqi/,3d' person.txt 
104,yy,CFO
105,feixue,CIO

命令說明:這個例子是刪除包含“chensiqi”的行到第3行的內容。但這種組合有一個比較特殊的情況,如果前3行之外還有這個“chensiqi”字眼,sed軟件還是會找他“麻煩”,請看下面例子。

[root@chensiqi1 ~]# sed '$a 106,chensiqi,CMO' person.txt 
101,chensiqi,CEO
102,zhangyang,CTO
103,Alex,COO
104,yy,CFO
105,feixue,CIO
106,chensiqi,CMO

命令說明:為了不造成同學們實驗文本改來改去導致不同意,因此我用上面的命令語句只是臨時修改內存數據,然后通過管道符號傳給sed軟件。

[root@chensiqi1 ~]# sed '$a 106,chensiqi,CMO' person.txt | sed '/chensiqi/,3d'
104,yy,CFO
105,feixue,CIO

命令說明:從命令結果我們可以看到,不僅是第1行(101,chensiqi,CEO)到第3行(103,ALex,COO)被刪除了,而且最后一行(106,chensiqi,CMO)也被刪除了。因此我們可以得出一個小結論,sed軟件使用正則表達式會找出所有匹配的行,即使是有數字地址限制。

再來看一個特殊情況。

[root@chensiqi1 ~]# sed '2,/O/d' person.txt 
101,chensiqi,CEO
104,yy,CFO
105,feixue,CIO

命令說明:
    從第2行開始刪除到含字母O的行結束,但是我們發現第3,4,5行都含有字母O,命令結果顯示只刪除了第2,3行,屬于最短刪除。這個怎么理解?
    還是可以從上面命令執行流程圖理解,從第2行開始循環,sed軟件第一次遇到字母O(第三行)就認為循環結束了。
[root@chensiqi1 ~]# sed '2,/o/d' person.txt 
101,chensiqi,CEO

命令說明:
    從第2行開始刪除,但是后面文本沒有字母O,因此一直循環下去,直到文本結束,sed軟件自動終止。

大家看完上面的例子是不是一臉懵逼,其實很簡單。在工作中我們最常用的還是數字地址這種精確匹配方式,像上面的正則地址或混合地址這種模糊匹配用的比較少,了解即可。

6.2.2.2 特殊符號~(步長)解析

格式:“First~step”表示從開始,以步長step遞增,這個在數學中叫做等差數列

例子:

  • 1~2 匹配1,3,5,7.....#-->用于只輸出奇書行,大伙仔細觀察一下每個數字的差值。
  • 2~2 匹配2,4,6,8....#-->用于只輸出偶數行
  • 1~3 匹配1,4,7,10.....
  • 2~3 匹配2,5,8,11.....
[root@chensiqi1 ~]# seq 10
1
2
3
4
5
6
7
8
9
10

命令說明:seq命令能夠生成從1到10的數字序列。

[root@chensiqi1 ~]# seq 10 | sed -n '1~2p'
1
3
5
7
9

命令說明:
    上面的命令主要驗證特殊符號“~”的效果,其他sed命令用法n和p請見后文詳解,大家只需要知道這個命令可以將“1~2”指定的行顯示出來即可。
    上面例子測試了“1~2”的效果,大家也可以手動測試一下“2~2”,“1~3”,“2~3”,看一下他們的結果是不是符合等差數列。

補充小知識:

如果大家想生成奇數數列,其實上面的方法是為了舉例,并不是一個很好的方法,因為seq命令自帶這種功能。

[root@chensiqi1 ~]# seq 1 2 10
1
3
5
7
9

命令說明:seq命令格式seq起始值 公差 結束值

再來一例:

[root@chensiqi1 ~]# sed '1~2d' person.txt 
102,zhangyang,CTO
104,yy,CFO

命令說明:“1~2”這是指定行數的另一種格式,從第1行開始以步長2遞增的行(1,3,5),因此刪掉第1,3,5行,即所有的奇數行。
6.2.2.3 特殊符號+解析
[root@chensiqi1 ~]# sed '1,+2d' person.txt  
104,yy,CFO
105,feixue,CIO

命令說明:這其實是做個加法運算,‘1,+2d’==>刪除第1行到第3(1+2)行的文本。

上面是特殊符號“+”的用法,大家知道即可。

6.2.2.4 特殊符號!解析

感嘆號“!”我們在很多命令里都接觸過,大部分都是取反的意思,在sed中也不例外。

[root@chensiqi1 ~]# sed '2,3!d' person.txt 
102,zhangyang,CTO
103,Alex,COO

命令說明:在地址范圍“2,3”后面加上“
!”,如果不加“!”表示刪除第2行和第3行,結果如下面的例子所示,然后加上“!”的結果就是除了第2行和第3行以外的內容都刪除,這個方法可以作為顯示文件的第2,3行題目的補充方法。

[root@chensiqi1 ~]# sed '2,3d' person.txt 
101,chensiqi,CEO
104,yy,CFO
105,feixue,CIO

企業案例2:打印文件內容但不包含chensiqi

這是一道企業面試題,很簡單,就是把包含chensiqi字符串的行刪除掉即可。我們可以用“grep -v”取反得到我們想要的結果,但是這里我們使用sed軟件實現。

[root@chensiqi1 ~]# sed '/chensiqi/d' person.txt 
102,zhangyang,CTO
103,Alex,COO
104,yy,CFO
105,feixue,CIO

命令說明:刪除包含“chensiqi”的行,就直接用正則匹配字符串chensiqi即可

6.2.3 改

大家現在已經學完了sed軟件2大招式,是不是很厲害!當然后面還有更厲害的--->改.在學習linux時,我們最常見的操作就是改配置文件,改參數等等,而且更妙的是前面我們學習過的增加和刪除其實都可以用我們準備要學的修改變相實現。

6.2.3.1 按行替換

首先說一下按行替換,這個功能用的很少,所以大家了解即可。這里用到的sed命令是:
“c”:用新行取代舊行,記憶方法:c的全拼是change,意思是替換。

例子:

[root@chensiqi1 ~]# sed '2c 106,dandan,CSO' person.txt 
101,chensiqi,CEO
106,dandan,CSO
103,Alex,COO
104,yy,CFO
105,feixue,CIO

命令說明:使用sed命令c將原來第2行“102,zhangyang,CTO”替換成“106,dandan,CSO”,整行替換
6.2.3.2 文本替換
  • 接下來說的這個功能,有工作經驗的同學應該非常的熟悉,因為使用sed軟件80%的場景就是使用替換功能。
  • 這里用到的sed命令,選項:
    “s”:單獨使用-->將每一行中第一處匹配的字符串進行替換==>sed命令
    “g”:每一行進行全部替換-->sed命令s的替換標志之一(全局替換),非sed命令。
    “-i”:修改文件內容-->sed軟件的選項,注意和sed命令i區別。

sed軟件替換模型

sed -i 's/目標內容/替換內容/g' chensiqi.log
sed -i 's#目標內容#替換內容#g'

觀察特點

1,兩邊是引號,引號里面的兩邊分別為s和g,中間是三個一樣的字符/或#作為定界符。字符#能在替換內容包含字符/有助于區別。定界符可以是任意字符如:或|等,但當替換內容包含定界符時,需要轉義:或|.經過長期實踐,建議大家使用#作為定界符。
2,定界符/或#,第一個和第二個之間的就是被替換的內容,第二個和第三個之間的就是替換后的內容。
3,s#目標內容#替換內容#g ,“目標內容”能用正則表達式,但替換內容不能用,必須是具體的。因為替換內容使用正則的話會讓sed軟件無所適從,它不知道你要替換什么內容。
4,默認sed軟件是對模式空間(內存中的數據)操作,而-i選項會更改磁盤上的文件內容。

例子:

[root@chensiqi1 ~]# sed 's#zhangyang#dandan#g' person.txt 
101,chensiqi,CEO
102,dandan,CTO
103,Alex,COO
104,yy,CFO
105,feixue,CIO

命令說明:將需要替換的文本“zhangyang”放在第一個和第二個“#”之間,將替換后的文本“dandan”放在第二個核第三個“#”之間。結果為第二行的“zhangyang”替換為“dandan”。

修改文件:

[root@chensiqi1 ~]# cat person.txt 
101,chensiqi,CEO
102,zhangyang,CTO
103,Alex,COO
104,yy,CFO
105,feixue,CIO

命令說明:從上面命令的結果我們就知道sed命令默認不會修改文件的內容

[root@chensiqi1 ~]# sed -i 's#zhangyang#dandan#g' person.txt

命令說明:如果想真正的修改文件內容,我們就需要使用選項“-i”,這個要和sed命令“i”區分開來。同時我們可以發現命令執行后的結果是沒有任何輸出的。

[root@chensiqi1 ~]# cat person.txt 
101,chensiqi,CEO
102,dandan,CTO
103,Alex,COO
104,yy,CFO
105,feixue,CIO

命令說明:當我們再次查看這個文件時,我們就發現這個文件已經被修改成功了。因此大家以后如果使用替換功能時,應該首先不用選項“-i”測試一下,確保操作無誤,最后使用“-i”修改文件

還原測試文件:

[root@chensiqi1 ~]# sed -i 's#dandan#zhangyang#g' person.txt

命令說明:還原測試文件,這一步大家不要忘了執行,不然后面就跟不上步驟了

企業案例3:指定行修改配置文件

前面我們學過的模型能夠將文件中所有滿足條件的文本進行操作,但是我們也會碰到指定行精確修改配置文件的需求,因為這樣可以避免修改多了地方。

[root@chensiqi1 ~]# sed '3s#0#9#' person.txt 
101,chensiqi,CEO
102,zhangyang,CTO
193,Alex,COO
104,yy,CFO
105,feixue,CIO

命令說明:
    前面學習的例子在sed命令“s”前沒有指定地址范圍,因此默認是對所有行進行操作。
    而這個案例要求只將第3行的0換成9,這里就用到了我們前面學過的地址范圍知識,在sed命令“s”前加上“3”就代表對第3行進行替換
6.2.3.3 變量替換

變量替換其實和前面的文本替換是一樣的,就是具體的文本變成了變量,同時要求大家對引號的用法要有清晰的理解,因此對雙引號和單引號的區別不太理解的同學,請往前面翻頁到【引號的區別總結】再次復習一下。

[root@chensiqi1 ~]# cat >test.txt<<KOF #再新建一個簡單的測試文本
> a
> b
> a
> KOF
[root@chensiqi1 ~]# cat test.txt 
a
b
a
[root@chensiqi1 ~]# x=a #->設置變量x并 賦值a
[root@chensiqi1 ~]# y=b #-> 設置變量y并賦值b
[root@chensiqi1 ~]# echo $x
a
[root@chensiqi1 ~]# echo $x $y
a b

命令說明:打印變量x,y驗證一下,需要使用$符號引用變量

不使用引號:

[root@chensiqi1 ~]# sed s#$x#$y#g test.txt 
b
b
b

命令說明:使用變量進行替換,從執行結果中我們可以發現替換成功了,test.txt文件中所有的a都替換成了b。同時我們可以發現s#$x#$y#g沒有使用引號,當然這種寫法并不是特別標準。

[root@chensiqi1 ~]# sed 's#'$x'#'$y'#g' test.txt 
b
b
b

命令說明:表面看起來單引號是可以用的,但其實這里用了障眼法,在你們眼中分段‘$x’和'$y',但其實分段是‘s#’和‘#’和‘#g’,所以$x和$y并沒有被引號擴起來,和上面的例子就一樣了。

使用eval命令:

[root@chensiqi1 ~]# eval sed 's#$x#$y#g' test.txt 
b
b
b

命令說明:這里給大家擴展一個Linux內置命令eval,這個命令能讀入變量,并將他們組合成一個新的命令,然后執行。首先eval會解析變量$x和變量$y,最后達到的效果和雙引號是一樣的。

擴展:最快速的獲取IP地址的方法

[root@chensiqi1 ~]# hostname -I
192.168.197.133 
6.2.3.4 分組替換()和\1的使用說明

sed軟件的()的功能可以記住正則表達式的一部分,其中,\1為第一個記住的模式即第一個小括號中的匹配內容,\2第二個記住的模式,即第二個小括號中的匹配內容,sed最多可以記住9個。

例:echo "I am chensiqi teacher."如果想保留這一行的單詞chensiqi,刪除剩下部分,使用圓括號標記想保留的部分。

[root@chensiqi1 ~]# echo "I am chensiqi teacher." | sed 's#^.*am \([a-z]\+\) tea.*$#\1#g'
chensiqi

[root@chensiqi1 ~]# echo "I am chensiqi teacher." | sed -r 's#^.*am ([a-z]+) tea.*$#\1#g'
chensiqi

[root@chensiqi1 ~]# echo "I am chensiqi teacher." | sed -r 's#I (.*) (.*) teacher.#\1\2#g'
amchensiqi

命令說明:
sed如果不加-r后綴,那么默認不支持擴展正則表達式,需要\符號進行轉義。小括號的作用是將括號里的匹配內容進行分組以便在第2和第3個#號之間進行sed的反向引用,\1代表引用第一組,\2代表引用第二組

再來看個題目:請執行命令取出linux中的eth0的IP地址?

[root@chensiqi1 ~]# ifconfig eth0 | sed -n '2p'
          inet addr:192.168.197.133  Bcast:192.168.197.255  Mask:255.255.255.0
[root@chensiqi1 ~]# ifconfig eth0 | sed -n '2p' | sed -r 's#^.*addr:(.*) Bcast:.*$#\1#g'
192.168.197.133 

也可以進行組合

[root@chensiqi1 ~]# ifconfig eth0 | sed -rn '2s#^.*addr:(.*) Bcast:.*$#\1#gp'
192.168.197.133 

命令說明:
這道題是需要把ifconfig eth0執行結果的第2行的IP地址取出來,上面答案的思路是用IP地址來替換第2行的內容。

企業案例4:系統開機啟動項優化(利用sed)

[root@chensiqi1 ~]# chkconfig --list | egrep -v  "sshd|crond|rsyslog|sysstat|network" | awk '{print $1}' |sed -r 's#^(.*)#chkconfig \1 off#g' |bash

這題也可以應用awk直接一步到位
[root@chensiqi1 ~]# chkconfig --list | egrep -v "sshd|crond|network|rsyslog|sysstat" | awk '{print "chkconfig",$1,"off"}' | bash
6.2.3.5 特殊符號&代表被替換的內容

這是一個特殊技巧,在適合的場景使用特別方便。下面用特殊符號“&”與分組替換一起使用,進行對比。

[root@chensiqi1 ~]# sed -r 's#(.*),(.*),(.*)#& ----- \1 \2 \3#' person.txt 
101,chensiqi,CEO ----- 101 chensiqi CEO
102,zhangyang,CTO ----- 102 zhangyang CTO
103,Alex,COO ----- 103 Alex COO
104,yy,CFO ----- 104 yy CFO
105,feixue,CIO ----- 105 feixue CIO

命令說明:
    1,這里將分組替換和&符號放在一起對比
    2,命令中的分組替換使用了3個小括號,每個小括號分別代表每一行以逗號作為分隔符的每一列。
    3,上面命令的&符號代表每一行,即模型中‘s#目標內容#替換內容#g’的目標內容。

企業案例5:批量重命名文件
當前目錄下有文件如下所示:

[root@chensiqi1 chen]# find ./ -name "*_finished.jpg"
./stu_102999_1_finished.jpg
./stu_102999_5_finished.jpg
./stu_102999_3_finished.jpg
./stu_102999_2_finished.jpg
./stu_102999_4_finished.jpg

要求用sed命令重命名,效果為
stu_102999_1_finished.jpg==>stu_102999_1.jpg,即刪除文件名的_finished

解題思路:因為這是文件名,不能直接yongsed命令替換,因此還需要借助mv命令重命名,格式為:mv stu_102999_1_finished.jpg stu_102999_1.jpg.我們需要拼湊這樣的格式,然后使用bash命令執行即可。

[root@chensiqi1 chen]# find ./ -name "*_finished.jpg" | sed -r 's#^(.*)_finished(.*)#\1\2#g'
./stu_102999_1.jpg
./stu_102999_5.jpg
./stu_102999_3.jpg
./stu_102999_2.jpg
[root@chensiqi1 chen]# find ./ -name "*_finished.jpg" | sed -r 's#^(.*)_finished(.*)#& \1\2#g' 
./stu_102999_1_finished.jpg ./stu_102999_1.jpg
./stu_102999_5_finished.jpg ./stu_102999_5.jpg
./stu_102999_3_finished.jpg ./stu_102999_3.jpg
./stu_102999_2_finished.jpg ./stu_102999_2.jpg
./stu_102999_4_finished.jpg ./stu_102999_4.jpg
[root@chensiqi1 chen]# find ./ -name "*_finished.jpg" | sed -r 's#^(.*)_finished(.*)#mv & \1\2#g' 
mv ./stu_102999_1_finished.jpg ./stu_102999_1.jpg
mv ./stu_102999_5_finished.jpg ./stu_102999_5.jpg
mv ./stu_102999_3_finished.jpg ./stu_102999_3.jpg
mv ./stu_102999_2_finished.jpg ./stu_102999_2.jpg
mv ./stu_102999_4_finished.jpg ./stu_102999_4.jpg
[root@chensiqi1 chen]# find ./ -name "*_finished.jpg" | sed -r 's#^(.*)_finished(.*)#mv & \1\2#g' |bash
[root@chensiqi1 chen]# ls
stu_102999_1.jpg  stu_102999_2.jpg  stu_102999_3.jpg  stu_102999_4.jpg  stu_102999_5.jpg

命令說明:
1.“\1”代表前面“(^.*)”匹配內容,“&”代表“s# #”里被替換的內容,這里匹配到的是完整的文件名。
2.使用bash命令執行,bash命令執行標準輸入的語句,如同我們在命令行輸入語句后敲回車。

6.2.4 查

  • 學到這里,大家可以稍微喘口氣了,因為sed里最常用最重要的我們已經學完了,接下來我們輕松的學完最后一招-->查看文本
  • 這個功能也是非常得有用,比如我們想查看文件中的某些行,以前最常用的是cat或more或less命令等,但這些命令有些缺點,就是不能查看指定的行。而我們用了很久的sed命令就有了這個功能了。而且我們前面也說過使用sed比其他命令vim等讀取速度更快!
  • 這里我們需要用到1個sed命令
  • “p”:輸出指定內容,但默認會輸出2次匹配的結果,因此使用-n選項取消默認輸出,記憶方法:p的全拼是print,意思是打印。
6.2.4.1 按行查詢
[root@chensiqi1 ~]# sed '2p' person.txt 
101,chensiqi,CEO
102,zhangyang,CTO
102,zhangyang,CTO
103,Alex,COO
104,yy,CFO
105,feixue,CIO
[root@chensiqi1 ~]# sed -n '2p' person.txt 
102,zhangyang,CTO

命令說明:選項-n取消默認輸出,只輸出匹配的文本,大家只需要記住使用命令p必用選項-n。

[root@chensiqi1 ~]# sed -n '2,3p' person.txt 
102,zhangyang,CTO
103,Alex,COO

命令說明:查看文件的第2行到3行,使用地址范圍“2,3”。取行就用sed,最簡單

[root@chensiqi1 ~]# sed -n '1~2p' person.txt 
101,chensiqi,CEO
103,Alex,COO
105,feixue,CIO

命令說明:打印文件的1,3,5行。~代表步長

[root@chensiqi1 ~]# sed -n 'p' person.txt 
101,chensiqi,CEO
102,zhangyang,CTO
103,Alex,COO
104,yy,CFO
105,feixue,CIO

命令說明:不指定地址范圍,默認打印全部內容。
6.2.4.2 按字符串查詢
[root@chensiqi1 ~]# sed -n '/CTO/p' person.txt 
102,zhangyang,CTO

命令說明:打印含CTO的行

[root@chensiqi1 ~]# sed -n '/CTO/,/CFO/p' person.txt 
102,zhangyang,CTO
103,Alex,COO
104,yy,CFO

命令說明:打印含CTO的行到含CFO的行。
6.2.4.3 混合查詢
[root@chensiqi1 ~]# sed -n '2,/CFO/p' person.txt 
102,zhangyang,CTO
103,Alex,COO
104,yy,CFO

命令說明:打印第2行到含CFO的行。

[root@chensiqi1 ~]# sed -n '/feixue/,2p' person.txt 
105,feixue,CIO

命令說明:特殊情況,前兩行沒有匹配到feixue,就向后匹配,如果匹配到feixue就打印此行。所以這種混合地址不推薦使用。
6.2.4.4 過濾多個字符
[root@chensiqi1 ~]# sed -rn '/chensiqi|yy/p' person.txt 
101,chensiqi,CEO
104,yy,CFO

命令說明:
    使用擴展正則“|”,為了不使用轉義符號“\”,因此使用-r選項開啟擴展正則表達式模式

7,sed命令應用知識擴展

7.1 sed修改文件的同時進行備份

[root@chensiqi1 ~]# cat person.txt 
101,chensiqi,CEO
102,zhangyang,CTO
103,Alex,COO
104,yy,CFO
105,feixue,CIO
[root@chensiqi1 ~]# sed -i.bak 's#zhangyang#NB#g' person.txt 
[root@chensiqi1 ~]# cat person.txt
101,chensiqi,CEO
102,NB,CTO
103,Alex,COO
104,yy,CFO
105,feixue,CIO
[root@chensiqi1 ~]# cat person.txt.bak 
101,chensiqi,CEO
102,zhangyang,CTO
103,Alex,COO
104,yy,CFO
105,feixue,CIO

命令行說明:
    在-i參數的后邊加上.bak(.任意字符),sed會對文件進行先備份后修改

7.2 特殊符號=獲取行號

[root@chensiqi1 ~]# sed '=' person.txt
1
101,chensiqi,CEO
2
102,NB,CTO
3
103,Alex,COO
4
104,yy,CFO
5
105,feixue,CIO

命令說明:使用特殊符號“=”就可以獲取文件的行號,這是特殊用法,記住即可。從上面的命令結果我們也發現了一個不好的地方:行號和行不在一行。

[root@chensiqi1 ~]# sed '1,3=' person.txt
1
101,chensiqi,CEO
2
102,NB,CTO
3
103,Alex,COO
104,yy,CFO
105,feixue,CIO

命令說明:只打印1,2,3行的行號,同時打印輸出文件中的內容

[root@chensiqi1 ~]# sed '/yy/=' person.txt
101,chensiqi,CEO
102,NB,CTO
103,Alex,COO
4
104,yy,CFO
105,feixue,CIO

命令說明:
    只打印正則匹配行的行號,同時輸出文件中的內容

[root@chensiqi1 ~]# sed -n '/yy/=' person.txt
4

命令說明:只顯示行號但不顯示行的內容即取消默認輸出。

[root@chensiqi1 ~]# sed -n '$=' person.txt
5

命令說明:
    “$”代表最后一行,因此顯示最后一行的行號,變相得出文件的總行數。

方法改進:

[root@chensiqi1 ~]# sed '=' person.txt | sed 'N;s#\n# #'
1 101,chensiqi,CEO
2 102,NB,CTO
3 103,Alex,COO
4 104,yy,CFO
5 105,feixue,CIO

命令說明:前面sed獲取文件的行號有一個缺點,我們這里使用Sed命令N來補償這個缺點。Sed命令N讀取下一行數據并附加到模式空間。

7.3 sed如何取不連續的行

[root@chensiqi1 ~]# sed -n '1p;3p;5p' person.txt
101,chensiqi,CEO
103,Alex,COO
105,feixue,CIO

7.4 特殊符號{}的使用

[root@chensiqi1 ~]# sed -n '2,4p;=' person.txt
1
102,NB,CTO
2
103,Alex,COO
3
104,yy,CFO
4
5

命令說明:-n去掉默認輸出,2,4p,輸出2到4行內容,=輸出全部的行的行號

[root@chensiqi1 ~]# sed -n '2,4{p;=}' person.txt
102,NB,CTO
2
103,Alex,COO
3
104,yy,CFO
4

命令說明:
    ‘2,4{p;=}’代表統一輸出2,4行的行號和內容

文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()