
- Unix/Linux 初學者指南
- Unix/Linux - 首頁
- Unix/Linux - 什麼是Linux?
- Unix/Linux - 入門
- Unix/Linux - 檔案管理
- Unix/Linux - 目錄
- Unix/Linux - 檔案許可權
- Unix/Linux - 環境
- Unix/Linux - 基本實用程式
- Unix/Linux - 管道和過濾器
- Unix/Linux - 程序
- Unix/Linux - 通訊
- Unix/Linux - vi編輯器
- Unix/Linux Shell程式設計
- Unix/Linux - Shell指令碼
- Unix/Linux - 什麼是Shell?
- Unix/Linux - 使用變數
- Unix/Linux - 特殊變數
- Unix/Linux - 使用陣列
- Unix/Linux - 基本運算子
- Unix/Linux - 決策
- Unix/Linux - Shell迴圈
- Unix/Linux - 迴圈控制
- Unix/Linux - Shell替換
- Unix/Linux - 引號機制
- Unix/Linux - I/O重定向
- Unix/Linux - Shell函式
- Unix/Linux - 手冊頁幫助
- 高階Unix/Linux
- Unix/Linux - 標準I/O流
- Unix/Linux - 檔案連結
- Unix/Linux - 正則表示式
- Unix/Linux - 檔案系統基礎
- Unix/Linux - 使用者管理
- Unix/Linux - 系統性能
- Unix/Linux - 系統日誌
- Unix/Linux - 訊號和陷阱
Unix/Linux - 使用sed的正則表示式
在本章中,我們將詳細討論Unix中使用sed的正則表示式。
正則表示式是一個可以用來描述多個字元序列的字串。許多不同的Unix命令都使用正則表示式,包括ed、sed、awk、grep,以及在有限程度上vi。
這裡SED代表stream editor(流編輯器)。這個面向流的編輯器專門用於執行指令碼。因此,您輸入的所有內容都會透過並輸出到STDOUT,它不會更改輸入檔案。
呼叫sed
在開始之前,讓我們確保我們有一個/etc/passwd文字檔案的本地副本,以便與sed一起使用。
如前所述,sed可以透過將資料透過管道傳送到它來呼叫,如下所示:
$ cat /etc/passwd | sed Usage: sed [OPTION]... {script-other-script} [input-file]... -n, --quiet, --silent suppress automatic printing of pattern space -e script, --expression = script ...............................
cat命令將/etc/passwd的內容透過管道轉儲到sed,進入sed的模式空間。模式空間是sed用於其操作的內部工作緩衝區。
sed通用語法
以下是sed的通用語法:
/pattern/action
這裡,pattern是正則表示式,action是下表中給出的命令之一。如果省略pattern,則對每一行執行action,如上所示。
圍繞模式的斜槓字元(/)是必需的,因為它們用作分隔符。
序號 | 範圍和描述 |
---|---|
1 |
p 列印行 |
2 |
d 刪除行 |
3 |
s/pattern1/pattern2/ 將pattern1的第一個出現替換為pattern2 |
使用sed刪除所有行
我們現在將瞭解如何使用sed刪除所有行。再次呼叫sed;但sed現在應該使用編輯命令刪除行,由單個字母d表示:
$ cat /etc/passwd | sed 'd' $
而不是透過管道將檔案傳送到sed來呼叫sed,sed可以被指示從檔案讀取資料,如下例所示。
以下命令與前面的示例完全相同,無需cat命令:
$ sed -e 'd' /etc/passwd $
sed地址
sed還支援地址。地址要麼是檔案中的特定位置,要麼是應該應用特定編輯命令的範圍。當sed遇到沒有地址時,它會在檔案中的每一行上執行其操作。
以下命令為sed命令添加了一個基本地址:
$ cat /etc/passwd | sed '1d' |more daemon:x:1:1:daemon:/usr/sbin:/bin/sh bin:x:2:2:bin:/bin:/bin/sh sys:x:3:3:sys:/dev:/bin/sh sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/bin/sh man:x:6:12:man:/var/cache/man:/bin/sh mail:x:8:8:mail:/var/mail:/bin/sh news:x:9:9:news:/var/spool/news:/bin/sh backup:x:34:34:backup:/var/backups:/bin/sh $
請注意,數字1是在刪除編輯命令之前新增的。這指示sed對檔案的第一行執行編輯命令。在本例中,sed將刪除/etc/password的第一行並列印檔案的其餘部分。
sed地址範圍
我們現在將瞭解如何使用sed地址範圍。那麼,如果您想從檔案中刪除多行怎麼辦?您可以使用sed指定地址範圍,如下所示:
$ cat /etc/passwd | sed '1, 5d' |more games:x:5:60:games:/usr/games:/bin/sh man:x:6:12:man:/var/cache/man:/bin/sh mail:x:8:8:mail:/var/mail:/bin/sh news:x:9:9:news:/var/spool/news:/bin/sh backup:x:34:34:backup:/var/backups:/bin/sh $
上述命令將應用於從1到5的所有行。這將刪除前五行。
嘗試以下地址範圍:
序號 | 範圍和描述 |
---|---|
1 |
'4,10d' 從第4行到第10行都被刪除 |
2 |
'10,4d' 僅刪除第10行,因為sed不反向工作 |
3 |
'4,+5d' 這匹配檔案中的第4行,刪除該行,繼續刪除接下來的五行,然後停止刪除並列印其餘部分 |
4 |
'2,5!d' 這刪除除第2行到第5行之外的所有內容 |
5 |
'1~3d' 這刪除第一行,跳過接下來的三行,然後刪除第四行。sed繼續應用此模式,直到檔案結束。 |
6 |
'2~2d' 這告訴sed刪除第二行,跳過下一行,刪除下一行,並重復直到檔案結束 |
7 |
'4,10p' 列印從第4行到第10行 |
8 |
'4,d' 這會產生語法錯誤 |
9 |
',10d' 這也會產生語法錯誤 |
注意 - 使用p操作時,應使用-n選項避免重複列印行。檢查以下兩個命令之間的區別:
$ cat /etc/passwd | sed -n '1,3p' Check the above command without -n as follows − $ cat /etc/passwd | sed '1,3p'
替換命令
替換命令(由s表示)將替換您指定的任何字串與您指定的任何其他字串。
為了用另一個字串替換一個字串,sed需要知道第一個字串在哪裡結束以及替換字串在哪裡開始的資訊。為此,我們繼續使用正斜槓(/)字元將兩個字串括起來。
以下命令將一行上root字串的第一次出現替換為amrood字串。
$ cat /etc/passwd | sed 's/root/amrood/' amrood:x:0:0:root user:/root:/bin/sh daemon:x:1:1:daemon:/usr/sbin:/bin/sh ..........................
需要注意的是,sed只替換一行上的第一次出現。如果字串root在一行上出現多次,則只替換第一個匹配項。
為了使sed執行全域性替換,請在命令末尾新增字母g,如下所示:
$ cat /etc/passwd | sed 's/root/amrood/g' amrood:x:0:0:amrood user:/amrood:/bin/sh daemon:x:1:1:daemon:/usr/sbin:/bin/sh bin:x:2:2:bin:/bin:/bin/sh sys:x:3:3:sys:/dev:/bin/sh ...........................
替換標誌
除了g標誌之外,還可以傳遞許多其他有用的標誌,並且您可以一次指定多個標誌。
序號 | 標誌和描述 |
---|---|
1 |
g 替換所有匹配項,而不僅僅是第一個匹配項 |
2 |
NUMBER 僅替換第NUMBER個匹配項 |
3 |
p 如果進行了替換,則列印模式空間 |
4 |
w FILENAME 如果進行了替換,則將結果寫入FILENAME |
5 |
I或i 不區分大小寫地匹配 |
6 |
M或m 除了特殊正則表示式字元^和$的正常行為之外,此標誌還會導致^匹配換行符後的空字串,以及$匹配換行符前的空字串 |
使用備用字串分隔符
假設您必須對包含正斜槓字元的字串進行替換。在這種情況下,您可以透過在s之後提供指定的字元來指定不同的分隔符。
$ cat /etc/passwd | sed 's:/root:/amrood:g' amrood:x:0:0:amrood user:/amrood:/bin/sh daemon:x:1:1:daemon:/usr/sbin:/bin/sh
在上面的示例中,我們使用了:作為分隔符而不是斜槓/,因為我們試圖搜尋/root而不是簡單的root。
用空格替換
使用空替換字串從/etc/passwd檔案中完全刪除root字串:
$ cat /etc/passwd | sed 's/root//g' :x:0:0::/:/bin/sh daemon:x:1:1:daemon:/usr/sbin:/bin/sh
地址替換
如果只想在第10行將字串sh替換為字串quiet,可以如下指定:
$ cat /etc/passwd | sed '10s/sh/quiet/g' root:x:0:0:root user:/root:/bin/sh daemon:x:1:1:daemon:/usr/sbin:/bin/sh bin:x:2:2:bin:/bin:/bin/sh sys:x:3:3:sys:/dev:/bin/sh sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/bin/sh man:x:6:12:man:/var/cache/man:/bin/sh mail:x:8:8:mail:/var/mail:/bin/sh news:x:9:9:news:/var/spool/news:/bin/sh backup:x:34:34:backup:/var/backups:/bin/quiet
同樣,要進行地址範圍替換,您可以執行以下操作:
$ cat /etc/passwd | sed '1,5s/sh/quiet/g' root:x:0:0:root user:/root:/bin/quiet daemon:x:1:1:daemon:/usr/sbin:/bin/quiet bin:x:2:2:bin:/bin:/bin/quiet sys:x:3:3:sys:/dev:/bin/quiet sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/bin/sh man:x:6:12:man:/var/cache/man:/bin/sh mail:x:8:8:mail:/var/mail:/bin/sh news:x:9:9:news:/var/spool/news:/bin/sh backup:x:34:34:backup:/var/backups:/bin/sh
從輸出中可以看到,前五行將字串sh更改為quiet,但其餘行保持不變。
匹配命令
您將使用p選項以及-n選項列印所有匹配行,如下所示:
$ cat testing | sed -n '/root/p' root:x:0:0:root user:/root:/bin/sh [root@ip-72-167-112-17 amrood]# vi testing root:x:0:0:root user:/root:/bin/sh daemon:x:1:1:daemon:/usr/sbin:/bin/sh bin:x:2:2:bin:/bin:/bin/sh sys:x:3:3:sys:/dev:/bin/sh sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/bin/sh man:x:6:12:man:/var/cache/man:/bin/sh mail:x:8:8:mail:/var/mail:/bin/sh news:x:9:9:news:/var/spool/news:/bin/sh backup:x:34:34:backup:/var/backups:/bin/sh
使用正則表示式
在匹配模式時,您可以使用正則表示式,它提供了更大的靈活性。
檢查以下示例,該示例匹配以daemon開頭的所有行,然後刪除它們:
$ cat testing | sed '/^daemon/d' root:x:0:0:root user:/root:/bin/sh bin:x:2:2:bin:/bin:/bin/sh sys:x:3:3:sys:/dev:/bin/sh sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/bin/sh man:x:6:12:man:/var/cache/man:/bin/sh mail:x:8:8:mail:/var/mail:/bin/sh news:x:9:9:news:/var/spool/news:/bin/sh backup:x:34:34:backup:/var/backups:/bin/sh
以下示例刪除所有以sh結尾的行:
$ cat testing | sed '/sh$/d' sync:x:4:65534:sync:/bin:/bin/sync
下表列出了正則表示式中四個非常有用的特殊字元。
序號 | 字元和描述 |
---|---|
1 |
^ 匹配行的開頭 |
2 |
$ 匹配行的結尾 |
3 |
. 匹配任何單個字元 |
4 |
* 匹配前一個字元的零個或多個出現 |
5 |
[chars] 匹配chars中給出的任何一個字元,其中chars是字元序列。您可以使用-字元表示字元範圍。 |
匹配字元
檢視一些其他的表示式來演示元字元的使用。例如,以下模式:
序號 | 表示式和描述 |
---|---|
1 |
/a.c/ 匹配包含a+c、a-c、abc、match和a3c等字串的行 |
2 |
/a*c/ 匹配相同的字串以及ace、yacc和arctic等字串 |
3 |
/[tT]he/ 匹配字串The和the |
4 |
/^$/ 匹配空行 |
5 |
/^.*$/ 匹配任何一行 |
6 |
/ */ 匹配一個或多個空格 |
7 |
/^$/ 匹配空行 |
下表顯示了一些常用的字元集:
序號 | 集合和描述 |
---|---|
1 |
[a-z] 匹配單個小寫字母 |
2 |
[A-Z] 匹配單個大寫字母 |
3 |
[a-zA-Z] 匹配單個字母 |
4 |
[0-9] [0-9] |
5 |
匹配單個數字 [a-zA-Z0-9] |
匹配單個字母或數字
字元類關鍵字
一些特殊關鍵字通常可用於正則表示式,尤其是使用正則表示式的GNU實用程式。它們對於sed正則表示式非常有用,因為它們簡化了操作並增強了可讀性。
例如,字元a到z和字元A到Z構成一類字元,其關鍵字為[[:alpha:]]
$ cat /etc/syslog.conf | sed -n '/^[[:alpha:]]/p' authpriv.* /var/log/secure mail.* -/var/log/maillog cron.* /var/log/cron uucp,news.crit /var/log/spooler local7.* /var/log/boot.log
使用字母字元類關鍵字,此命令僅列印/etc/syslog.conf檔案中以字母開頭的那些行:
序號 | 下表是GNU sed中所有可用字元類關鍵字的完整列表。 |
---|---|
1 |
字元類和描述 [[:alnum:]] |
2 |
字母數字 [a-z A-Z 0-9] [[:alpha:]] |
3 |
字母 [a-z A-Z] [[:blank:]] |
4 |
空白字元(空格或製表符) [[:cntrl:]] |
5 |
控制字元 [[:digit:]] |
6 |
數字 [0-9] [[:graph:]] |
7 |
任何可見字元(不包括空格) [[:lower:]] |
8 |
小寫字母 [a-z] [[:print:]] |
9 |
可列印字元(非控制字元) [[:punct:]] |
10 |
標點符號 [[:space:]] |
11 |
[[:upper:]] 大寫字母 [A-Z] |
12 |
[[:xdigit:]] 十六進位制數字 [0-9 a-f A-F] |
&符號引用
sed 元字元 & 代表匹配到的模式內容。例如,假設你有一個名為 phone.txt 的檔案,其中包含以下電話號碼:
5555551212 5555551213 5555551214 6665551215 6665551216 7775551217
你想將區號(前三位數字)用括號括起來,以便於閱讀。為此,你可以使用&符號替換字元:
$ sed -e 's/^[[:digit:]][[:digit:]][[:digit:]]/(&)/g' phone.txt (555)5551212 (555)5551213 (555)5551214 (666)5551215 (666)5551216 (777)5551217
在這裡,在模式部分,你匹配前 3 位數字,然後使用& 將這 3 位數字替換為周圍的括號。
使用多個 sed 命令
你可以在單個 sed 命令中使用多個 sed 命令,如下所示:
$ sed -e 'command1' -e 'command2' ... -e 'commandN' files
這裡,command1 到 commandN 是前面討論過的型別的 sed 命令。這些命令應用於 files 指定的檔案列表中的每一行。
使用相同的機制,我們可以將上述電話號碼示例編寫如下:
$ sed -e 's/^[[:digit:]]\{3\}/(&)/g' \ -e 's/)[[:digit:]]\{3\}/&-/g' phone.txt (555)555-1212 (555)555-1213 (555)555-1214 (666)555-1215 (666)555-1216 (777)555-1217
注意 - 在上面的示例中,我們用\{3\}替換了字元類關鍵字[[:digit:]]三次重複,這意味著前面的正則表示式匹配三次。我們還使用了\來換行,在執行命令之前必須將其刪除。
反向引用
&符號元字元很有用,但更有用的是能夠在正則表示式中定義特定區域。這些特殊區域可以用作替換字串中的引用。透過定義正則表示式的特定部分,然後可以使用特殊的引用字元引用這些部分。
要進行反向引用,首先需要定義一個區域,然後引用該區域。要定義一個區域,你需要在感興趣的每個區域周圍插入反斜槓括號。你用反斜槓括起來的第一個區域由\1引用,第二個區域由\2引用,依此類推。
假設phone.txt包含以下文字:
(555)555-1212 (555)555-1213 (555)555-1214 (666)555-1215 (666)555-1216 (777)555-1217
嘗試以下命令:
$ cat phone.txt | sed 's/\(.*)\)\(.*-\)\(.*$\)/Area \ code: \1 Second: \2 Third: \3/' Area code: (555) Second: 555- Third: 1212 Area code: (555) Second: 555- Third: 1213 Area code: (555) Second: 555- Third: 1214 Area code: (666) Second: 555- Third: 1215 Area code: (666) Second: 555- Third: 1216 Area code: (777) Second: 555- Third: 1217
注意 - 在上面的示例中,括號內的每個正則表示式將分別由\1、\2等進行反向引用。我們在這裡使用了\來換行。在執行命令之前應該將其刪除。