linux基礎命令介紹十:文本流編輯 sed

vim不一樣,sed是一種非交互式的文本編輯器,同時它又是面向字符流的,每行數據通過sed處理後輸出。ios

sed [OPTION]... [script] [file]...

sed的工做過程是這樣的:首先,初始化兩個數據緩衝區模式空間保持空間sed讀取一行輸入(來自標準輸入或文件),去掉結尾的換行符(\n)後置於模式空間中,而後針對模式空間中的字符串開始執行‘sed命令’,每一個命令均可以有地址與之相關聯,地址能夠當作是條件,只有在條件成立時,相關的命令才被執行;全部可執行命令都處理完畢後,仍處於模式空間中的字符串會被追加一個換行符後打印輸出;以後讀取下一行輸入作一樣的處理,直到主動退出(q)或輸入結束。正則表達式

地址

地址能夠是以下的形式vim

一、number 表示行號
二、first~step 表示從first(數字)行開始,每隔step(數字)行
三、$ 表示最後一行(注意當出如今正則表達式中時表示行尾)
四、/regexp/ 表示匹配正則表達式regexp(關於正則表達式,請參見這一篇)
五、\%regexp% 表示匹配正則表達式regexp,%能夠換成任意其餘單個字符。(用於regexp包含斜線/的狀況)
六、/regexp/I 匹配正則表達式regexp時不區分大小寫
七、/regexp/M 啓用正則多行模式,使$不止匹配行尾,還匹配\n或\r以前的位置;使^不止匹配行首,還匹配\n或\r以後的位置。此時能夠用(\`)匹配模式空間的開頭位置,用(\')匹配模式空間的結束位置。segmentfault

還能夠用逗號,分隔兩個地址來表示一個範圍windows

表示從匹配第一個地址開始,直到匹配第二個地址或文件結尾爲止。若是第二個地址是個正則表達式,則不會對第一個地址匹配行進行第二個地址的匹配;若是第二個地址是行號,但小於或等於第一個地址匹配行行號,則只會匹配一行(第一個地址匹配行)。centos

八、0,/regexp/ 這種狀況下,正則表達式regexp會在第一行就開始進行匹配。只有第二個地址是正則表達式時,第一個地址才能用0。
九、addr1,+n表示匹配地址addr1和其後的n行。
十、addr1,~n表示從匹配地址addr1開始,直到n的倍數行爲止。
若是沒有給出地址,全部的行都會匹配;在地址或地址範圍後追加字符!表示對地址取反,全部不匹配的行纔會被處理。bash

選項

-n 默認時每一行處理過的字符串都會被打印輸出,此選項表示關閉此默認行爲。只有被命令p做用的字符串纔會被輸出。
-f file表示從file中讀取sed命令
-i 表示原地修改。應用此選項時,sed會建立一個臨時文件,並將處理結果輸出到此文件,處理完畢後,會將此臨時文件覆蓋至原文件。
-r 表示使用擴展的正則表達式編輯器

命令

p表示打印模式空間內容,一般配合選項-n一塊兒使用centos7

[root@centos7 ~]# seq 5
1
2
3
4
5
[root@centos7 ~]# 只輸出第二行到第四行
[root@centos7 ~]# seq 5|sed -n '2,4p'
2
3
4
[root@centos7 ~]#

d 刪除模式空間內容,當即處理下一行輸入。code

#刪除最後一行
[root@centos7 ~]# seq 5|sed '$d'
1
2
3
4
[root@centos7 ~]#

q 當即退出,再也不處理任何命令和輸入(只接受單個地址)

[root@centos7 ~]# seq 5|sed '/3/q'
1
2
3
[root@centos7 ~]#

n 若是沒有使用選項-n,輸出模式空間中內容後,讀取下一行輸入並覆蓋當前模式空間內容。若是沒有更多的輸入行,sed會退出執行。

[root@centos7 ~]# seq 9|sed -n 'n;p'
2
4
6
8
[root@centos7 ~]# 注意多個命令用分號分隔

s/regexp/replacement/flag 表示用replacement替換模式空間中匹配正則表達式regexp的部分。在這裏符號/能夠換成任意單個字符。

[root@centos7 ~]# echo "hello123world"|sed 's/[0-9]\+/,/'  
hello,world
#注意這裏+須要轉義,若是使用選項-r則無需轉義

在replacement中

一、\n (n爲1-9中的一個數字)表示對正則表達式中分組(...)的引用;

[root@centos7 ~]# echo "hello123world"|sed -r 's/[a-z]+([0-9]+)[a-z]+/\1/'
123
[root@centos7 ~]# echo "hello123world"|sed -r 's/([a-z]+)[0-9]+([a-z]+)/\1,\2/'
hello,world

二、&表示模式空間中全部匹配regexp的部分;

[root@centos7 ~]# echo "hello123world"|sed -r 's/[0-9]+/:&:/'
hello:123:world

三、\L 將後面的字符轉化成小寫直到 \U 或 \E 出現;
四、\l 將下一個字符轉化爲小寫;
五、\U 將後面的字符轉化成大寫直到 \L 或 \E 出現;
六、\u 將下一個字符轉化爲大寫;
七、\E 中止由 \L 或 \U 起始的大小寫轉化;

[root@centos7 ~]# echo "hello123world"|sed -r 's/^([a-z]+)[0-9]+([a-z]+)$/\U\1\E,\u\2/'
HELLO,World
[root@centos7 ~]#

flag

一、n數字n表示替換第n個匹配項

[root@centos7 ~]# head -1 /etc/passwd
root:x:0:0:root:/root:/bin/bash
#替換冒號分隔的第五部分爲空
[root@centos7 ~]# head -1 /etc/passwd|sed 's/[^:]\+://5'
root:x:0:0:/root:/bin/bash

二、g表示全局替換

[root@centos7 ~]# echo "hello123world"|sed 's/./\U&\E/'
Hello123world
[root@centos7 ~]# 
[root@centos7 ~]# echo "hello123world"|sed 's/./\U&\E/g'
HELLO123WORLD
[root@centos7 ~]#
#當數字n和g同時使用時,表示從第n個匹配項開始替換一直到最後匹配項
[root@centos7 ~]# head -1 /etc/passwd|sed 's/[^:]\+://4g'
root:x:0:/bin/bash/

三、p表示若是替換成功,則打印模式空間內容。
四、w file表示若是替換成功,則輸出模式空間內容至文件file中。
五、Ii表示匹配regexp時不區分大小寫。

[root@centos7 ~]# echo 'HELLO123world'|sed -r 's/[a-z]+//Ig'
123
[root@centos7 ~]#

六、Mm表示啓用正則多行模式(如前所述)。(講命令N時再舉例)

y/source-chars/dest-chars/把source-chars中的字符替換爲dest-chars中對應位置的字符,/能夠換爲其餘任意單個字符,source-chars和dest-chars中字符數量必須一致且不能用正則表達式。

[root@centos7 ~]# echo hello|sed 'y/el/LE/'      
hLEEo
[root@centos7 ~]#

a text表示輸出模式空間內容後追加輸出text內容

[root@centos7 ~]# seq 3|sed '1,2a hello' 
1
hello
2
hello
3
[root@centos7 ~]#

i text表示輸出模式空間內容以前,先輸出text內容

[root@centos7 ~]# seq 3|sed '$ihello'
1
2
hello
3
[root@centos7 ~]#

c text表示刪除匹配地址或地址範圍的模式空間內容,輸出text內容。若是是單地址,則每一個匹配行都輸出,若是是地址範圍,則只輸出一次。

[root@centos7 ~]# seq 5|sed '1,3chello'
hello
4
5
[root@centos7 ~]# seq 5|sed '/^[^3-4]/c hello' 
hello
hello
3
4
hello

=表示打印當前輸入行行號

[root@centos7 ~]# seq 100|sed -n '$='
100
[root@centos7 ~]# seq 100|sed -n '/^10\|^20/='
10
20
100
[root@centos7 ~]# 轉義的|表示邏輯或

r file表示讀取file的內容,並在當前模式空間內容輸出以後輸出

[root@centos7 ~]# cat file 
hello world
[root@centos7 ~]# seq 3|sed '1,2r file'
1
hello world
2
hello world
3
[root@centos7 ~]#

w file表示輸出模式空間內容至file中

N讀入一行內容至模式空間後,再追加下一行內容至模式空間(此時模式空間中內容形如 line1\nline2 ),若是不存在下一行,sed會退出。

[root@centos7 ~]# seq 10|sed -n 'N;s/\n/ /p'
1 2
3 4
5 6
7 8
9 10
[root@centos7 ~]#
#s命令的m flag舉例
[root@centos7 ~]# seq 3|sed 'N;s/^2/xxx/' 
1
2
3
[root@centos7 ~]# seq 3|sed 'N;s/^2/xxx/m'    
1
xxx
3
[root@centos7 ~]# seq 3|sed 'N;s/1$/xxx/' 
1
2
3
[root@centos7 ~]# seq 3|sed 'N;s/1$/xxx/M'
xxx
2
3

D若是模式空間中沒有新行(如命令N產生的新行),則和命令d起一樣做用;若是包含新行,則會刪除第一行內容,而後對模式空間中剩餘內容從新開始一輪處理。(注意:D後面的命令將會被忽略)

[root@centos7 ~]# seq 5|sed 'N;D'  
5
[root@centos7 ~]# seq 5|sed 'N;N;D'   
3
4
5

P打印模式空間中第一行內容

[root@centos7 ~]# seq 10|sed -n 'N;P' 
1
3
5
7
9
[root@centos7 ~]# seq 10|sed -n 'N;N;P'
1
4
7
#注意另外一種寫法輸出中的不一樣
[root@centos7 ~]# seq 10|sed -n '1~3P' 
1
4
7
10

g用保持空間中的內容替換模式空間中的內容

[root@centos7 ~]# seq 5|sed -n 'g;N;s/\n/xx/p'
xx2
xx4
[root@centos7 ~]#

G追加一個換行符到模式空間,而後再將保持空間中的內容追加至換行符以後。(此時模式空間中內容形如 PATTERN\nHOLD )

[root@centos7 ~]# seq 5|sed 'G;s/\n/xx/'  
1xx
2xx
3xx
4xx
5xx

h用模式空間中的內容替換保持空間中的內容(注意此時模式空間中的內容並無被清除)

[root@centos7 ~]# seq 5|sed -n 'h;G;s/\n/xx/p'
1xx1
2xx2
3xx3
4xx4
5xx5
[root@centos7 ~]# seq 5|sed -n 'h;G;G;s/\n/xx/gp'
1xx1xx1
2xx2xx2
3xx3xx3
4xx4xx4
5xx5xx5

H追加一個換行符到保持空間,而後再將模式空間中的內容追加至換行符以後。(此時保持空間中內容形如 HOLD\nPATTERN )

[root@centos7 ~]# seq 3|sed -n 'H;G;s/\n/xx/gp'
1xxxx1
2xxxx1xx2
3xxxx1xx2xx3
[root@centos7 ~]#

x交換模式空間和保持空間的內容

[root@centos7 ~]# seq 9|sed -n '1!{x;N};s/\n//p'
3
25
47
69
#處於{...}之中的是命令組

: label爲分支命令指定標籤位置(不容許地址匹配)

b label無條件跳轉到label分支,若是省略了label,則跳轉到整條命令結尾(即開始下一次讀入)

#如刪除xml文件中註釋部分(<!--...-->之間的部分是註釋,能夠多行)
sed '/<!--/{:a;/-->/!{N;ba};d}' server.xml
#表示匹配<!--開始,在匹配到-->以前一直執行N,匹配到-->以後刪除模式空間中內容
#如在nagios的配置文件中,有許多define host{...}的字段,以下所示:
define host{
use windows-server
host_name serverA
hostgroups 060202
alias 060202
contact_groups yu
address 192.168.1.1
}
#如今須要刪除ip地址是192.168.1.1的段,能夠這樣:
sed -i '/define host/{:a;N;/}/!ba;/192\.168\.1\.1/d}' file
#注意和前一個例子中的區別

t label在一次輸入後有成功執行的s替換命令才跳轉到label,若是省略了label,則跳轉到整條命令結尾(即開始下一次讀入)

#如行列轉換
[root@centos7 ~]# seq 10|sed ':a;$!N;s/\n/,/;ta'
1,2,3,4,5,6,7,8,9,10
[root@centos7 ~]#
#如將MAC地址78A35114F798改爲帶冒號的格式78:A3:51:14:F7:98
[root@centos7 temp]# echo '78A35114F798'|sed -r ':a;s/\B\w{2}\b/:&/;ta'
78:A3:51:14:F7:98
[root@centos7 temp]#
#這裏\b表示匹配單詞邊界,\B表示匹配非單詞邊界的其餘任意字符
#固然也能夠採用其餘的方式實現:
[root@centos7 temp]# echo '78A35114F798'|sed -r 's/..\B/&:/g'
78:A3:51:14:F7:98
[root@centos7 temp]#

T label在一次輸入後只要沒有替換命令被成功執行就跳轉到label,若是省略了label,則跳轉到整條命令結尾(即開始下一次讀入)

z表示清除模式空間中內容,和s/.*//起相同的做用,但更有效。

更多例子

一、刪除匹配行的上一行和下一行

#例如輸入數據爲命令seq 10的輸出(固然也能夠是任意其餘文件內容)
#要求刪除匹配5那一行的前一行和後一行
[root@centos7 temp]# seq 10|sed -n '$!N;/\n5/{s/.*\n//p;N;d};P;D'
1
2
3
5
7
8
9
10

二、合併奇偶數行

#輸入數據爲命令seq 11的輸出,要求分別將奇數和偶數分別放在同一行
#輸出第一行`1 3 5 7 9 11`,第二行`2 4 6 8 10`
[root@centos7 ~]# seq 11|sed -nr '$!N;2!G;s/([^\n]+)\n((.+)\n)?(.+)\n(.+)/\4 \1\n\5 \3/;h;$p'
1 3 5 7 9 11
2 4 6 8 10 
[root@centos7 ~]#

三、合併多文件

#文本a.txt的內容:
01 12510101 4001
02 12310001 4002
03 12550101 4003
04 12610001 4004
05 12810001 4005
06 12310001 4006
07 12710001 4007
08 12310001 4008
09 12810101 4009
10 12510101 4010
11 12310001 4011
12 12610001 4012
13 12310001 4013
#文本b.txt的內容:
A 12410101 2006/02/15 2009/01/31 4002
B 12310001 2006/08/31 2008/08/29 4001
C 12610001 2008/05/23 2008/05/22 4002
D 12810001 1992/12/10 1993/06/30 4001
E 12660001 1992/05/11 1993/06/01 4005
#要求輸出a.txt內容中第二列和b.txt中第二列相同的行,並追加b.txt中對應的兩個日期列。
#形如:02 12310001 4002 2006/08/31 2008/08/29
sed -rn '/^[01]/ba;H;:a;G;s/^((..)( .*)( [^\n]+)).*\3(( [^ ]*){2}).*/\1\5/p' b.txt a.txt
#固然若是使用awk來處理的話,解決思路更容易理解一些:
awk 'NR==FNR{a[$2]=$3FS$4;next}{if($2 in a)print $0,a[$2]}' b.txt a.txt

爲加深對sed各類命令特性的理解,請自行分析這三個例子。

各類命令的組合使用,再加上正則表達式的強大能力,使得sed能夠處理全部可以計算的問題。但因爲代碼可讀性不強,理解起來比較困難,一般使用sed做爲一個文本編輯器,對文本作非交互的流式處理。理解上述各個命令的含義,熟練使用它們,就會發現sed的強大之處。

相關文章
相關標籤/搜索