正規表示式是一個字串,它可以用來描述幾個字元序列。使用正規表示式是由幾個不同的Unix命令,包括 ed, sed, awk, grep,並且,在較為有限的程度上擴充套件 vi.
本教學將教你如何使用正規表示式使用 sed.
這裡流編輯器sed的代表是面向流的編輯器,它是專門用於執行指令碼建立。因此,所有的輸入送入通過到stdout,它不會改變輸入檔案。
在我們開始之前,讓我們確保你有一個本地副本 /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 的一般語法
/pattern/action
在這裡,模式是一個正規表示式,動作是下表中給出的命令之一。如果省略模式,執行操作的每一行,正如我們上面看到的。
斜線字元(/),環繞模式是必需的,因為它們被用來作為分隔符。
Range | 描述 |
---|---|
p | Prints the line |
d | Deletes the line |
s/pattern1/pattern2/ | Substitutes the first occurrence of pattern1 with pattern2. |
再次呼叫sed ,但這個時候告訴sed使用編輯命令刪除行,由單字母d表示:
$ cat /etc/passwd | sed 'd' $
呼叫sed 傳送檔案,通過管道,而是可以指示sed來讀取資料檔案,在下面的例子。
下面的命令做完全一樣的東西,以前的嘗試,沒有 cat 命令:
$ sed -e 'd' /etc/passwd $
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,您可以指定一個地址範圍如下:
$ 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 -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,依此類推。在這裡,我用斷行執行此命令之前你應該刪除。