全網最詳細的Linux命令系列-sed文本處理命令

Sed簡介

SED是一個非交互式文本編輯器,它可對文本文件和標準輸入進行編輯,標準輸入能夠來自鍵盤輸入、文本重定向、字符串、變量,甚至來自於管道的文本,與VIM編輯器相似,它一次處理一行內容,Sed能夠編輯一個或多個文件,簡化對文件的反覆操做、編寫轉換程序等。html

Sed命令的原理:在處理文本時把當前處理的行存儲在臨時緩衝區中,稱爲「模式空間」(pattern space),緊接着用SED命令處理緩衝區中的內容,處理完成後把緩衝區的內容輸出至屏幕或者寫入文件。逐行處理直到文件末尾,然而若是打印在屏幕上,實質文件內容並無改變,除非你使用重定向存儲輸出或者寫入文件。linux

Sed語法參數

參數格式爲:正則表達式

sed    [-Options]     [‘Commands’]    filename;

sed工具默認處理文本,文本內容輸出屏幕已經修改,可是文件內容其實沒有修改,須要加-i參數即對文件完全修改;shell

-e<script>或--expression=<script>   以選項中指定的script來處理輸入的文本文件。
-f<script文件>或--file=<script文件>   以選項中指定的script文件來處理輸入的文本文件。
-h                                      或--help 顯示幫助。
-n或--quiet或--silent                僅顯示script處理後的結果。
-r  使用擴展正則表達式
x                               #x爲指定行號;
x,y                             #指定從x到y的行號範圍;
/pattern/                       #查詢包含模式的行;
/pattern/,/pattern/             #查詢包含兩個模式的行;
/pattern/,x                     #從與pattern的匹配行到x號行之間的行;
x,/pattern/                     #從x號行到與pattern的匹配行之間的行;
x,y!                            #查詢不包括x和y行號的行;
r                                 #從另外一個文件中讀文件;
w                                 #將文本寫入到一個文件;
y                                 #變換字符;
q                                     #第一個模式匹配完成後退出;
l                                 #顯示與八進制ASCII碼等價的控制字符;
{}                                #在定位行執行的命令組;
p                                 #打印匹配行;
=                                 #打印文件行號;
a\                                #在定位行號以後追加文本信息;
i\                                #在定位行號以前插入文本信息;
d                                 #刪除定位行;
c\                                #用新文本替換定位文本;
s                                 #使用替換模式替換相應模式;
&                           #引用已匹配字符串
first~step                  #步長,每 step 行,從第 first 開始
$                           #匹配最後一行
/regexp/                    #正則表達式匹配行
number                      #只匹配指定行
addr1,addr2                 #開始匹配 addr1 行開始,直接 addr2 行結束
addr1,+N                    #從 addr1 行開始,向後的 N 行
addr1,~N                    #從 addr1 行開始,到 N 行結束

Sed實例練習(模式空間)

示例文本:express

[root@localhost ~]# cat test.txt 
www.test.net
www.baidu.com
www.taobao.com
www.sina.com
old old old
new new new

替換test.txt文本中old爲new:bash

sed    's/old/new/g'       test.txt

打印test.txt文本第一行至第三行:tcp

sed    -n  '1,3p'           test.txt

打印test.txt文本中第一行與最後一行:編輯器

sed    -n '1p;$p'           test.txt

刪除test.txt第一行至第三行、刪除匹配行至最後一行:工具

sed       '1,3d'             test.txt
sed       '/test/,$d'         test.txt

刪除test.txt最後6行及刪除最後一行:post

for   i  in `seq 1 6`;do  sed  -i   '$d'  test.txt ;done
sed       '$d'               test.txt

刪除test.txt最後一行:

sed       '$d'             test.txt

在test.txt查找test所在行,並在其下一行添加word字符,a表示在其下一行添加字符串:

sed    '/test/aword'      test.txt

在test.txt查找test所在行,並在其上一行添加word字符,i表示在其上一行添加字符串:

sed    '/test/i word'       test.txt

在test.txt查找以test結尾的行尾添加字符串word,$表示結尾標識,&在Sed中表示添加:

sed   's/test$/& word/g'     test.txt

在test.txt查找www的行,在其行首添加字符串word,^表示起始標識,&在Sed中表示添加:

sed   '/www/s/^/& word/'    test.txt

多個sed命令組合,使用-e參數:

sed  -e  '/www.jd.com/s/^/&1./'  -e  's/www.jd.com$/&./g'  test.txt

多個sed命令組合,使用分號「;」分割:

sed  -e  '/www.jd.com/s/^/&1./;s/www.jd.com$/&./g'  test.txt

Sed讀取系統變量,變量替換:

TEST=WWW.test.NET
Sed  「s/www.jd.com/$TEST/g」 test.txt

修改Selinux策略enforcing爲disabled,查找/SELINUX/行,而後將其行enforcing值改爲disabled、!s表示不包括SELINUX行:

sed  -i   '/SELINUX/s/enforcing/disabled/g' /etc/selinux/config
sed  -i   '/SELINUX/!s/enforcing/disabled/g' /etc/selinux/config

去除空格httpd.conf文件空行或者是#號開頭的行

sed '/^#/d;/^$/d' /etc/httpd/conf/httpd.conf

打印是把匹配的打印出來,刪除是把匹配的刪除,刪除只是不用-n 選項
IP 加單引號

echo '10.10.10.1 10.10.10.2 10.10.10.3' |sed -r 's/[^ ]+/"&"/g'
"10.10.10.1" "10.10.10.2" "10.10.10.3"

分組() 匹配

對 1-4 行的 html 進行替換
示例文件:

http://www.baidu.com/index.html
http://www.baidu.com/1.html
http://post.baidu.com/index.html
http://mp3.baidu.com/index.html
http://www.baidu.com/3.html
http://post.baidu.com/2.html
tail  /etc/services | sed '1,4 s/html/txt/'
http://www.baidu.com/index.txt
http://www.baidu.com/1.txt
http://post.baidu.com/index.txt
http://mp3.baidu.com/index.txt
http://www.baidu.com/3.html
http://post.baidu.com/2.html

分組使用,在第2列後面添加 test

tail /etc/services |sed -r 's/(.*) (.*)(#.*)/\1\2test \3/'
3gpp-cbsp 48049/tcp test # 3GPP Cell Broadcast Service
isnetserv 48128/tcp test # Image Systems Network Services
isnetserv 48128/udp test # Image Systems Network Services
blp5 48129/tcp test # Bloomberg locator
blp5 48129/udp test # Bloomberg locator
com-bardac-dw 48556/tcp test # com-bardac-dw
com-bardac-dw 48556/udp test # com-bardac-dw
iqobject 48619/tcp test # iqobject
iqobject 48619/udp test # iqobject 

第一列是第一個小括號匹配,第二列第二個小括號匹配,第三列同樣。將不變的字符串匹配分組,再經過\數字按分組順序反向引用。

基本正則表達式中支持分組,而在擴展正則表達式中,分組的功能更增強大,也能夠說纔是真正的分組

():分組,後面可使用\1 \2 \3...引用前面的括號分組。

處理如下文件內容,將域名取出並進行計數排序,如處理:

http://www.baidu.com/index.html
http://www.baidu.com/1.html
http://post.baidu.com/index.html
http://mp3.baidu.com/index.html
http://www.baidu.com/3.html
http://post.baidu.com/2.html

獲得以下結果:
域名的出現的次數域名

[root@localhost shell]# cat file | sed -e ' s/http:\/\///' -e ' s/\/.*//' | sort | uniq -c | sort -rn
3 www.baidu.com
2 post.baidu.com
1 mp3.baidu.com
[root@codfei4 shell]# awk -F/ '{print $3}' file |sort -r|uniq -c|awk '{print $1"\t",$2}'
3 www.baidu.com
2 post.baidu.com
1 mp3.baidu.com*

將協議與端口號位置調換

tail /etc/services |sed -r 's/(.*)(\<[0-9]+\>)\/(tcp|udp)(.*)/\1\3\/\2\4/'
3gpp-cbsp tcp/48049 # 3GPP Cell Broadcast Service
isnetserv tcp/48128 # Image Systems Network Services
isnetserv udp/48128 # Image Systems Network Services
blp5 tcp/48129 # Bloomberg locator
blp5 udp/48129 # Bloomberg locator
com-bardac-dw tcp/48556 # com-bardac-dw
com-bardac-dw udp/48556 # com-bardac-dw
iqobject tcp/48619 # iqobject
iqobject udp/48619 # iqobject
matahari tcp/49000 # Matahari Broker

字符位置調換
替換 x 字符爲大寫:

# echo "abc cde xyz" |sed -r 's/(.*)x/\1X/'
abc cde Xyz

456 與 cde 調換:

# echo "abc:cde;123:456" |sed -r 's/([^:]+)(;.*:)([^:]+$)/\3\2\1/'
abc:456;123:cde

註釋匹配行後的多少行

[root@localhost ~]# sed '/5/,+3s/^/@/' 1.txt 
1 
2 
3 
4 
@5 
@6 
@7 
@8 
9 
10

註釋指定多行

[root@localhost ~]# sed -r 's/^3|^5|^7/#&/' 1.txt 
1 
2 
#3 
4 
#5 
6 
#7 
8 
9 
10

去除開頭和結尾空格或製表符

echo " 1 2 3 " |sed 's/^[ \t]*//;s/[ \t]*$//'
1 2 3

Sed實例練習(保留空間)

Sed之因此能以行爲單位進行修改文本或者編輯文本,主要緣由是由於它使用了兩個空間:一個是活動的「模式空間」,另外一個是輔助做用的「保留空間」.
模式空間:能夠想象成工程裏面的流水線,全部的數據讀取過來以後就直接在上面進行工做。
保留空間:能夠想象成是倉庫,咱們在進行數據處理的時候,會把數據讀取到保留空間中,做爲數據的暫存區域,須要時再進行調出。

SED高級命令能夠分爲三種功能:

N、D、P:處理多行模式空間的問題;
H、h、G、g、x:將模式空間的內容放入保留空間以便接下來的編輯;
:、b、t:在腳本中實現分支與條件結構(標籤)。
n                              #讀取下一個輸入行,用下一個命令處理新的行;
N                        #將當前讀入行的下一行讀取到當前的模式空間。
d                                      #刪除模式空間的全部內容,開始下一個循環
D                        #刪除模式空間的第一行,開始下一個循環;
p                                      #打印當前模式空間的全部內容;
P                                      #打印模式空間的第一行,開始下一個循環
h                              #將模式緩衝區的文本複製到保持緩衝區;
H                              #將模式緩衝區的文本追加到保持緩衝區;
x                              #互換模式緩衝區和保持緩衝區的內容;
g                              #將保持緩衝區的內容複製到模式緩衝區;
G                              #將保持緩衝區的內容追加到模式緩衝區。

在test.txt每行後加入空行,也即每行佔永兩行空間,每一行後邊插入一行空行、兩行空行及前三行每行後插入空行:

sed     '/^$/d;G'            test.txt  #刪除的是匹配的條件行,留下的是模式空間處理的行,G參數是將保持空間內的行追加到模式空間去(保持空間默認是空的)。
sed     '/^$/d;G;G'            test.txt  #後面跟2個G 是將G保持空間內的兩行追加到模式空間
sed     '/^$/d;1,3G;'       test.txt     #1,3G 是隻將追加3行到模式空間

將test.txt偶數行刪除及隔兩行刪除一行:

sed    'n;d'              test.txt      #n參數將輸入行的下一行顯示出來,然後面的d 正好會將顯示的行進行刪除,測試「sed –n ‘n;p’ file 」
sed    'n;n;d'           test.txt,   #2個n參數將輸入的的下兩行顯示出來,正好使用d都刪除,造成隔兩行刪一行的效果。

在test.txt匹配行前一行、後一行插入空行以及同時在匹配先後插入空行:

sed  '/test/{x;p;x;}'      test.txt     #x參數是讓模式空間和保持空間互相交換,匹配test時,將模式空間內的數據換成了保持空間內的數據,保持空間默認是空的,因此前一行會變成空行,而後將空行打印出來
sed  '/test/G'                test.txt  #G參數配置上以後將保持空間的內容追加到模式空間去。
sed  '/test/{x;p;x;G;}'   test.txt      #綜合以上兩個參數配置。

在test.txt每行前加入順序數字序號、加上製表符\t及.符號:

sed = test.txt| sed 'N;s/\n/ /'   # 「=」等號打印當前行號碼。N參數是配置將當前讀入行的下一行讀取到當前的模式空間,就是把下一行讀到當前的模式空間來,利用s替換換行符,造成數字順序效果。
sed = test.txt| sed 'N;s/\n/\t/'  #案例同上
sed = test.txt| sed 'N;s/\n/\./'  #案例同上

刪除test.txt行前和行尾的任意空格:

sed 's/^[ \t]*//;s/[ \t]*$//' test.txt  #s替換 刪除行前

打印test.txt關鍵詞old與new之間的內容:

sed -n '/old/,/new/'p     test.txt   #-n參數能夠打印匹配的條件內容行

打印及刪除test.txt最後兩行:

sed   '$!N;$!D'             test.txt 
N  讀取下一行並追加輸入到模式空間
D  刪除模式空間的第一行,開始下一個循環
#讀取1,$!條件知足(不是尾行,#N前加$!表示末尾行不執行N),執行N命令,讀取下一行並追加輸入到模式空間,得出1\n2。執行$!D,不是最後一行,因此執行D,刪除模式空間的第一行,開始下一個循環,模式空間由1\n2成了2。讀取第二行,執行 N 命令,此時模式空間是 3\n4,執行 D 命令刪除模式空間第一行 3,剩餘4,直到執行N讀入第5行,$!條件不知足(不是尾行),不執行N命令:繼續讀入6行,這裏模式空間爲:5\n6,$!D,由於是最後一行,因此不執行D,控制流到達腳本底部,輸出模式空間的內容
sed   'N;$!P;$!D;$d'      test.txt
P  打印模式空間的第一行
N  讀取下一行並追加輸入到模式空間
D  刪除模式空間的第一行,開始下一個循環
d 刪除匹配的行
#讀取第一行,執行N,此時得出1\n2,P打印從開始到第一個\n的內容,執行$!D,不是最後一行,因此執行D,刪除模式空間的第一行,開始下一個循環,模式空間由1\n2成了2,$d 是由於不是末行因此不執行,讀取第二行,執行 N 命令,此時模式空間是 3\n4,執行 P 命令顯示模式空間第一行 3,執行D,刪除模式空間的第一行,剩餘4,讀取第5行,執行N,將第6行進行讀取,執行$!P,由於是最後一行不執行P,執行$!D,由於是最後一行,不執行D,最後執行$d,刪除模式空間5/6行。

合併上下兩行,也即兩行合併:

sed    '$!N;s/\n/ /'          test.txt  #N前加$!表示末尾行不執行N
sed    'N;s/\n/ /'            test.txt

Sed中標籤使用(: 、b 和 和 t )

標籤能夠控制流,實現分支判斷。

:           lable name 定義標籤
b       lable 跳轉到指定標籤,若是沒有標籤則到腳本末尾
t          lable 跳轉到指定標籤,前提是 s///命令執行成功

將換行符替換成逗號
方法 1:

seq 6 |sed 'N;s/\n/,/'
1,2
3,4
5,6

這種方式並不能知足咱們的需求,每次 sed 讀取到模式空間再打印是新行,替換\n 也只能對 N 命令,追加後的 1\n2 這樣替換。
這時就能夠用到標籤了:

seq 6 |sed ':a;N;s/\n/,/;b a'
1,2,3,4,5,6
看看這裏的標籤使用,:a 是定義的標籤名,b a 是跳轉到 a 位置。
sed 讀取第一行 1,N 命令讀取下一行 2,此時模式空間是 1\n2$,執行替換,此時模式空間是1,2$,執行 b 命令再跳轉到標籤 a 位置繼續執行 N 命令,讀取下一行 3 追加到模式空間,此時模式空間是 1,2\n3$,再替換,以此類推,不斷追加替換,直到最後一行 N 讀不到下一行內容退出。

方法 2:

seq 6 |sed ':a;N;$!b a;s/\n/,/g'
1,2,3,4,5,6
先將每行讀入到模式空間,最後再執行全局替換。$!是若是是最後一行,則不執行 b a 跳轉,最後執行全局替換。
seq 6 |sed ':a;N;b a;s/\n/,/g'
1
2
3
4
5
6
能夠看到,不加$!是沒有替換,由於循環到 N 命令沒有讀到行就退出了,後面的替換也就沒執行。

每三個數字加個一個逗號

# echo "123456789" |sed -r 's/([0-9]+)([0-9]+{3})/\1,\2/'

123456,789

# echo "123456789" |sed -r ':a;s/([0-9]+)([0-9]+{3})/\1,\2/;t a'

123,456,789

# echo "123456789" |sed -r ':a;s/([0-9]+)([0-9]+{2})/\1,\2/;t a'

1,23,45,67,89
執行第一次時,替換最後一個,跳轉後,再對 123456 匹配替換,直到匹配替換不成功,不執行 t 命令。

忽略大小寫匹配(I )

# echo -e "a\nA\nb\nc" |sed 's/a/1/Ig'

1
1
b
c

獲取總行數(# )

seq 10 |sed -n '$='

Sed 腳本使用編寫方法
<1>從文件讀入命令

sed -f sed.sh
sed.sh文件內容:
s/root/yerik/p
s/bash/csh/p

<2>直接運行腳本 ./sed.sh /etc/passwd

#!/bib/sed -f
s/root/yerik/p
s/bash/csh/p

Sed 擴展練習高級替換

1,刪除文件每行的第一個字符。

sed -n 's/^.//gp' /etc/passwd
sed -nr 's/(.)(.*)/\2/p' /etc/passwd
sed -r 's/^.//g' test.txt

2,刪除文件每行的第二個字符。

sed -nr 's/(.)(.)(.*)/\1\3/p' /etc/passwd
sed -r 's/(^.)(.)/\1/g' test.txt

3,刪除文件每行的最後一個字符。

sed -nr 's/.$//p' /etc/passwd
sed -nr 's/(.*)(.)/\1/p' /etc/passwd
sed -r 's/(.)$//g' test.txt

4,刪除文件每行的倒數第二個字符。

sed -nr 's/(.*)(.)(.)/\1\3/p' /etc/passwd
sed -r 's/(.)(.)$/\2/g' test.txt

5,刪除文件每行的第二個單詞。

sed -nr 's/([^a-Z]*)([a-Z]+)([^a-Z]+)([a-Z]+)(.*)/\1\2\3\5/p' /etc/passwd
sed -r 's/([a-Z]+)([^a-Z]+)([a-Z]+)([^a-Z]+)(.*)/\1\2\4\5/' test.txt

6,刪除文件每行的倒數第二個單詞。

sed -nr 's/(.*)([^a-Z]+)([a-Z]+)([^a-Z]+)([a-Z]+)([^a-Z]*)/\1\2\4\5\6/p' /etc/passwd
sed -r 's/([a-Z]+)([^a-Z])([a-Z]+)$/\2\3/g' test.txt

7,刪除文件每行的最後一個單詞。

sed -nr 's/(.*)([^a-Z]+)([a-Z]+)([^a-Z]*)/\1\2\4/p' /etc/passwd
sed -r 's/([a-Z]+)$//g' test.txt
sed -r 's/(.*)([^a-Z]+)([a-Z]+)/\1\2/' test.txt

8,交換每行的第一個字符和第二個字符。

sed -nr 's/(.)(.)(.*)/\2\1\3/p' /etc/passwd
sed -r 's/(.)(.)/\2\1/' test.txt

9,交換每行的第一個字符和第二個單詞

sed -r 's/(^.)([^a-Z]*)([a-Z]+)([^a-Z]+)([a-Z]+)/\5\2\3\4\1/' test.txt

9,交換每行的第一個單詞和第二個單詞。

sed -nr 's/([^a-Z]*)([a-Z]+)([^a-Z]+)([a-Z]+)(.*)/\1\4\3\2\5/p' /etc/passwd

10,交換每行的第一個單詞和最後一個單詞。

sed -r 's/([a-Z]+)([^a-Z]+)(.*)([^a-Z]+)([a-Z]+)/\5\2\3\4\1/' test.txt

11,刪除一個文件中全部的數字。

sed 's/[0-9]*//g' test.txt

12,刪除每行開頭的全部空格。

sed -n 's/^\ *//p' /etc/passwd 
sed -nr 's/( *)(.*)/\2/p' test.txt
sed 's/^ *//' test.txt

13,用製表符替換文件中出現的全部空格。

sed -n 's/\ /\t/gp' test.txt
sed -r 's/( +)/\t/g' test.txt
sed 's/ /\t/g' test.txt

14,把全部大寫字母用括號()括起來。

sed -nr 's/([A-Z])/(&)/gp' test.txt
sed -n 's/[A-Z]/(&)/gp' test.txt

15,打印每行3次。

sed 'p;p' test.txt
sed -n 'p;p;p'  test.txt

16,隔行刪除。

sed -n '1~2p' test.txt
sed '1d;n;d' ww.txt
sed '1~2d' ww.txt 
sed '0~2d' ww.txt

17,把文件從第22行到第33行復制到第44行後面。

sed '1,21h;22h;23,33H;44G' pass
cat -n /etc/passwd | sed '22h;23,33H;44G'

18,把文件從第22行到第33行移動到第44行後面。

sed '22{h;d};23,33{H;d};44G' pass
cat -n /etc/passwd | sed '22{h;d};23,33{H;d};44G'

19,只顯示每行的第一個單詞。

sed -nr 's/([^a-Z]*)([a-Z]+)([^a-Z]+)(.*)/\2/p' /etc/passwd
sed -r 's/([a-Z]+)(.*)/\1/'  test.txt

20,打印每行的第一個單詞和第三個單詞。

sed -nr 's/([^a-Z]*)([a-Z]+)([^a-Z]+)([a-Z]+)([^a-Z]+)([a-Z]+)(.*)/\2--\4/p' /etc/passwd
sed -r 's/([^a-Z]*)([a-Z]+)([^a-Z]+)([a-Z]+)([^a-Z]+)([a-Z]+)(.*)/\2\6/'  test.txt

21,將格式爲 mm/yy/dd 的日期格式換成 mm;yy;dd

date +%m/%Y/%d |sed -n 's#/#;#gp'

22, 逆向輸出

cat a.txt
ABC
DEF
XYZ
sed '1!G;h;$!d' a.txt
輸出樣式變成
XYZ
DEF
ABC

Sed 做業練習:

  1. 把/etc/passwd 複製到/root/test.txt,用sed打印全部行
  2. 打印test.txt的3到10行
  3. 打印test.txt 中包含 ‘root’ 的行
  4. 刪除test.txt 的15行以及之後全部行
  5. 刪除test.txt中包含 ‘bash’ 的行
  6. 替換test.txt 中 ‘root’ 爲 ‘toor’
  7. 替換test.txt中 ‘/sbin/nologin’ 爲 ‘/bin/login’
  8. 刪除test.txt中5到10行中全部的數字
  9. 刪除test.txt 中全部特殊字符(除了數字以及大小寫字母)
  10. 把test.txt中第一個單詞和最後一個單詞調換位置
  11. 把test.txt中出現的第一個數字和最後一個單詞替換位置
  12. 把test.txt 中第一個數字移動到行末尾
  13. 在test.txt 20行到末行最前面加 ‘aaa:’

sed習題答案

1. /bin/cp /etc/passwd  /root/test.txt ;  sed -n '1,$'p test.txt
2. sed -n '3,10'p test.txt
3. sed -n '/root/'p test.txt
4. sed '15,$'d  test.txt
5. sed '/bash/'d test.txt
6. sed 's/root/toor/g' test.txt
7. sed 's#sbin/nologin#bin/login#g' test.txt
8. sed '5,10s/[0-9]//g' test.txt
9. sed 's/[^0-9a-zA-Z]//g' test.txt
10. sed 's/\(^[a-Z]*\)\([^a-Z].*\)\([^a-Z]\)\([a-Z]*$\)/\4\2\3\1/' test.txt
11. sed 's#\([^0-9][^0-9]*\)\([0-9][0-9]*\)\([^0-9].*\)\([^a-zA-Z]\)\([a-zA-Z][a-zA-Z]*$\)#\1\5\3\4\2#' test.txt
12. sed 's#\([^0-9][^0-9]*\)\([0-9][0-9]*\)\([^0-9].*$\)#\1\3\2#' test.txt
13. sed '20,$s/^.*$/aaa:&/' test.txt
相關文章
相關標籤/搜索