您好,登錄后才能下訂單哦!
如何理解Linux基礎命令中文本流編輯sed命令,針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
與vim不同,sed是一種非交互式的文本編輯器,同時它又是面向字符流的,每行數據經過sed處理后輸出。
sed [OPTION]... [script] [file]...
sed的工作過程是這樣的:首先,初始化兩個數據緩沖區模式空間和保持空間;sed讀取一行輸入(來自標準輸入或文件),去掉結尾的換行符(\n)后置于模式空間中,然后針對模式空間中的字符串開始執行‘sed命令’,每個命令都可以有地址與之相關聯,地址可以看成是條件,只有在條件成立時,相關的命令才被執行;所有可執行命令都處理完畢后,仍處于模式空間中的字符串會被追加一個換行符后打印輸出;之后讀取下一行輸入做同樣的處理,直到主動退出(q)或輸入結束。
地址
地址可以是如下的形式
1、number 表示行號
2、first~step 表示從first(數字)行開始,每隔step(數字)行
3、$ 表示***一行(注意當出現在正則表達式中時表示行尾)
4、/regexp/ 表示匹配正則表達式regexp(關于正則表達式,請參見這一篇)
5、\%regexp% 表示匹配正則表達式regexp,%可以換成任意其他單個字符。(用于regexp包含斜線/的情況)
6、/regexp/I 匹配正則表達式regexp時不區分大小寫
7、/regexp/M 啟用正則多行模式,使$不止匹配行尾,還匹配n或r之前的位置;使^不止匹配行首,還匹配n或r之后的位置。此時可以用(\`)匹配模式空間的開頭位置,用(\')匹配模式空間的結束位置。
還可以用逗號,分隔兩個地址來表示一個范圍
表示從匹配***個地址開始,直到匹配第二個地址或文件結尾為止。如果第二個地址是個正則表達式,則不會對***個地址匹配行進行第二個地址的匹配;如果第二個地址是行號,但小于或等于***個地址匹配行行號,則只會匹配一行(***個地址匹配行)。
8、0,/regexp/ 這種情況下,正則表達式regexp會在***行就開始進行匹配。只有第二個地址是正則表達式時,***個地址才能用0。
9、addr1,+n表示匹配地址addr1和其后的n行。
10、addr1,~n表示從匹配地址addr1開始,直到n的倍數行為止。
如果沒有給出地址,所有的行都會匹配;在地址或地址范圍后追加字符!表示對地址取反,所有不匹配的行才會被處理。
選項
-n 默認時每一行處理過的字符串都會被打印輸出,此選項表示關閉此默認行為。只有被命令p作用的字符串才會被輸出。
-f file表示從file中讀取sed命令
-i 表示原地修改。應用此選項時,sed會創建一個臨時文件,并將處理結果輸出到此文件,處理完畢后,會將此臨時文件覆蓋至原文件。
-r 表示使用擴展的正則表達式
命令
p表示打印模式空間內容,通常配合選項-n一起使用
[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 刪除模式空間內容,立即處理下一行輸入。
#刪除***一行 [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中
1、\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
2、&表示模式空間中所有匹配regexp的部分;
[root@centos7 ~]# echo "hello123world"|sed -r 's/[0-9]+/:&:/' hello:123:world
3、\L 將后面的字符轉化成小寫直到 \U 或 \E 出現;
4、\l 將下一個字符轉化為小寫;
5、\U 將后面的字符轉化成大寫直到 \L 或 \E 出現;
6、\u 將下一個字符轉化為大寫;
7、\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
1、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
2、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/
3、p表示如果替換成功,則打印模式空間內容。
4、w file表示如果替換成功,則輸出模式空間內容至文件file中。
5、I和i表示匹配regexp時不區分大小寫。
[root@centos7 ~]# echo 'HELLO123world'|sed -r 's/[a-z]+//Ig' 123 [root@centos7 ~]#
6、M和m表示啟用正則多行模式(如前所述)。(講命令N時再舉例)
[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/.*//起相同的作用,但更有效。
更多例子
1、刪除匹配行的上一行和下一行
#例如輸入數據為命令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
2、合并奇偶數行
#輸入數據為命令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 ~]#
3、合并多文件
#文本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的強大之處。
關于如何理解Linux基礎命令中文本流編輯sed命令問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。