位置:首頁 > 其他技術 > Unix > Unix 正則表達式SED

Unix 正則表達式SED

正則表達式是一個字符串,它可以用來描述幾個字符序列。使用正則表達式是由幾個不同的Unix命令,包括 ed, sed, awk, grep,並且,在較為有限的程度上擴展 vi.

本教學將教你如何使用正則表達式使用 sed.

這裡流編輯器sed的代表是麵向流的編輯器,它是專門用於執行腳本創建。因此,所有的輸入送入通過到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

在這裡,模式是一個正則表達式,動作是下表中給出的命令之一。如果省略模式,執行操作的每一行,正如我們上麵看到的。

斜線字符(/),環繞模式是必需的,因為它們被用來作為分隔符。

Range 描述
p Prints the line
d Deletes the line
s/pattern1/pattern2/ Substitutes the first occurrence of pattern1 with pattern2.

用sed刪除所有行:

再次調用sed ,但這個時候告訴sed使用編輯命令刪除行,由單字母d表示:

$ cat /etc/passwd | sed 'd'
$

調用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,您可以指定一個地址範圍如下:

$ 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的所有行。所以,刪除前五行。

試試下麵的地址範圍:

Range 描述
'4,10d' Lines starting from 4th till 10th are deleted
'10,4d' Only 10th line is deleted, because sed does not work in reverse direction.
'4,+5d' This will match line 4 in the file, delete that line, continue to delete the next five lines, and then cease its deletion and print the rest
'2,5!d' This will deleted everything except starting from 2nd till 5th line.
'1~3d' This deletes the first line, steps over the next three lines, and then deletes the fourth line. Sed continues applying this pattern until the end of the file.
'2~2d' This tells sed to delete the second line, step over the next line, delete the next line, and repeat until the end of the file is reached.
'4,10p' Lines starting from 4th till 10th are printed
'4,d' This would generate syntax error.
',10d' This would also generate syntax error.

注:使用p動作時,你應該使用-n選項,以避免重複行式打印。檢查以下兩條命令之間的區彆:

$ cat /etc/passwd | sed -n '1,3p'

檢查上麵的命令冇有-n作為如下:

$ cat /etc/passwd | sed '1,3p'

替換命令:

替換命令,用s表示,將您指定的其他任何字符串中指定的任何字符串代替。

用一個字符串代替另一個,你需要有一些方式告訴sed,你的第一個字符串結束,並開始替換字符串。這是傳統上是由兩個字符串bookending斜線(/)字符。

首次出現一行字符串根字符串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的隻有第一次出現的行上。如果字符串根不止一次發生在一行的第一個匹配項將被替換。

告訴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標誌除了可以傳遞的標誌,你可以一次指定多個。

標誌 描述
g Replace all matches, not just the first match.
NUMBER Replace only NUMBERth match.
p If substitution was made, print pattern space.
w FILENAME If substitution was made, write result to FILENAME.
I or i Match in a case-insensitive manner.
M or m In addition to the normal behavior of the special regular expression characters ^ and $, this flag causes ^ to match the empty string after a newline and $ to match the empty string before a newline.

使用替代字符串分隔符:

您可能會發現自己不得不做一個替換在一個字符串,其中包含斜線字符。在這種情況下,您可以指定不同的分隔,提供指定的字符後的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

地址替換:

如果你想用quiet 在第10行字符串替換字符串的sh,您可以指定如下: 

$ 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,但其餘各行均保持不變。

匹配的命令:

你會使用-n選項一起使用p選項打印所有匹配的行,如下所示:

$ 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

使用正則表達式:

在匹配模式中,你可以使用正則表達式,它提供了更多的靈活性。

檢查下麵的例子匹配所有的行開始守護進程,然後刪除它們:

$ 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

下表列出了四個特殊字符在正則表達式中是非常有用的。

字符 描述
^ Matches the beginning of lines.
$ Matches the end of lines.
. Matches any single character.
* Matches zero or more occurrences of the previous character
[chars] Matches any one of the characters given in chars, where chars is a sequence of characters. You can use the - character to indicate a range of characters.

匹配字符:

看幾個表達式元字符演示使用。例如,下麵的模式:

表達式 描述
/a.c/ Matches lines that contain strings such as a+c, a-c, abc, match, and a3c, whereas the pattern
/a*c/ Matches the same strings along with strings such as ace, yacc, and arctic.
/[tT]he/ Matches the string The and the:
/^$/ Matches Blank lines
/^.*$/ Matches an entire line whatever it is.
/ */ Matches one or more spaces
/^$/ Matches Blank lines

下表列出了一些常用的字符集:

Set 描述
[a-z] Matches a single lowercase letter
[A-Z] Matches a single uppercase letter
[a-zA-Z] Matches a single letter
[0-9] Matches a single number
[a-zA-Z0-9] Matches a single letter or number

字符類關鍵詞:

一些特殊的關鍵字是常用的正則表達式,特彆是GNU工具,采用正則表達式。這些sed的正則表達式是非常有用的,因為它們簡化了的東西,增強可讀性。

例如,字符a到z以及A到Z的字符構成的字符的其中一類,具有關鍵字 [[:alpha:]]

使用字母字符類的關鍵字,隻有那些行在 /etc/syslog.conf 文件,一個字母開始,這個命令打印:

$ 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

下表是GNU sed的可用字符類中的關鍵字的完整列表。

Character Class 描述
[[:alnum:]] Alphanumeric [a-z A-Z 0-9]
[[:alpha:]] Alphabetic [a-z A-Z]
[[:blank:]] Blank characters (spaces or tabs)
[[:cntrl:]] Control characters
[[:digit:]] Numbers [0-9]
[[:graph:]] Any visible characters (excludes whitespace)
[[:lower:]] Lowercase letters [a-z]
[[:print:]] Printable characters (noncontrol characters)
[[:punct:]] Punctuation characters
[[:space:]] Whitespace
[[:upper:]] Uppercase letters [A-Z]
[[:xdigit:]] Hex digits [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

這裡命令通過commandN是前麵討論過的類型的sed命令。這些命令被施加到給定的文件的文件列表中的各行。

我們可以使用相同的機製,上麵寫的電話號碼的例子如下:

$ 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

注:在上麵的例子中,而不是重複字符類關鍵字 [[:digit:]]三次,取而代之的是{3},這意味著匹配前麵的正則表達式三次。在這裡,我用 斷行運行此命令之前你應該刪除。 

返回參考:

符號元字符是有用的,但更為有用的是能夠定義特定的區域,在一個正則表達式,這樣你就可以替換字符串中引用它們。通過定義一個正則表達式的特定部分,你可以參考那些部分特彆提到字符。

要做返回引用,你必須首先定義一個區域,然後參考該區域。要定義一個區域,你插入反斜杠括號,圍繞感興趣區域。環繞反斜杠第一區域,然後引用 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,依此類推。在這裡,我用斷行運行此命令之前你應該刪除。