第十二章、正規表示法與文件格式化處理

访客 阅读:26 2024-07-15 14:41:26 评论:0
美化布局示例

欧易(OKX)最新版本

【遇到注册下载问题请加文章最下面的客服微信】永久享受返佣20%手续费!

APP下载   全球官网 大陆官网

币安(Binance)最新版本

币安交易所app【遇到注册下载问题请加文章最下面的客服微信】永久享受返佣20%手续费!

APP下载   官网地址

火币HTX最新版本

火币老牌交易所【遇到注册下载问题请加文章最下面的客服微信】永久享受返佣20%手续费!

APP下载   官网地址
正規表示法 (Regular Expression, RE, 或稱為常規表示法)是透過一些特殊字元的排列,用以『搜尋/取代/刪除』一列或多列文字字串,簡單的說,正規表示法就是用在字串的處理上面的一項『表示式』。字串處理的標準依據

以行為單位
正規表示法與萬用字元是完全不一樣的東西!?
??
??
??
??
??
??
??
??
??
??
??
??
??

[root@www ~]# grep [-A] [-B] [--color=auto] '搜尋字串' filename
選項與參數:
-A :後面可加數字,為 after 的意思,除了列出該行外,後續的 n 行也列出來;
-B :後面可加數字,為 befer 的意思,除了列出該行外,前面的 n 行也列出來;
--color=auto 可將正確的那個擷取資料列出顏色

範例一:用 dmesg 列出核心訊息,再以 grep 找出內含 eth 那行
[root@www ~]# dmesg | grep 'eth'
eth0: RealTek RTL8139 at 0xee846000, 00:90:cc:a6:34:84, IRQ 10
eth0:  Identified 8139 chip type 'RTL-8139C'
eth0: link up, 100Mbps, full-duplex, lpa 0xC5E1
eth0: no IPv6 routers present
# dmesg 可列出核心產生的訊息!透過 grep 來擷取網路卡相關資訊 (eth) ,
# 就可發現如上資訊。不過沒有行號與特殊顏色顯示!看看下個範例吧!

範例二:承上題,要將捉到的關鍵字顯色,且加上行號來表示:
[root@www ~]# dmesg | grep -n --color=auto 'eth'
247:eth0: RealTek RTL8139 at 0xee846000, 00:90:cc:a6:34:84, IRQ 10
248:eth0:  Identified 8139 chip type 'RTL-8139C'
294:eth0: link up, 100Mbps, full-duplex, lpa 0xC5E1
305:eth0: no IPv6 routers present
# 你會發現除了 eth 會有特殊顏色來表示之外,最前面還有行號喔!

範例三:承上題,在關鍵字所在行的前兩行與後三行也一起捉出來顯示
[root@www ~]# dmesg | grep -n -A3 -B2 --color=auto 'eth'
245-PCI: setting IRQ 10 as level-triggered
246-ACPI: PCI Interrupt 0000:00:0e.0[A] -> Link [LNKB] ...
247:eth0: RealTek RTL8139 at 0xee846000, 00:90:cc:a6:34:84, IRQ 10
248:eth0:  Identified 8139 chip type 'RTL-8139C'
249-input: PC Speaker as /class/input/input2
250-ACPI: PCI Interrupt 0000:00:01.4[B] -> Link [LNKB] ...
251-hdb: ATAPI 48X DVD-ROM DVD-R-RAM CD-R/RW drive, 2048kB Cache, UDMA(66)
# 如上所示,你會發現關鍵字 247 所在的前兩行及 248 後三行也都被顯示出來!
# 這樣可以讓你將關鍵字前後資料捉出來進行分析啦!



小標題的圖示 基礎正規表示法練習

要瞭解正規表示法最簡單的方法就是由實際練習去感受啦!所以在彙整正規表示法特殊符號前,我們先以底下這個檔案的內容來進行正規表示法的理解吧!先說明一下,底下的練習大前提是:

The simplest way to understand the formal expression is to be experienced by practical practice; so before the full rule expression special sign xff0c; let's start with the content of the file below xff01; let's start with xff0c; let's start with xff0c; the main premise below is xff1a;

  • 語系已經使用『 export LANG=C 』的設定值;
  • grep 已經使用 alias 設定成為『 grep --color=auto 』

至於本章的練習用檔案請由底下的連結來下載。需要特別注意的是,底下這個檔案是鳥哥在 MS Windows 系統下編輯的,並且已經特殊處理過,因此,他雖然是純文字檔,但是內含一些 Windows 系統下的軟體常常自行加入的一些特殊字元,例如斷行字元 (^M) 就是一例!所以,你可以直接將底下的文字以 vi 儲存成 regular_express.txt 這個檔案,不過,還是比較建議直接點底下的連結:

As for the practice file for this chapter, it should be downloaded from the link below. Special attention needs to be paid to xff0c; the file below is xff0c, edited by Brother Bird under the MS Windows system; and xff0c; thus xff0c; he may be a plain text file xff0c; but contains some special characters xff0c, which are often added by Windows software; for example, a breakword character (M) is an example xff01; xff0c; you can save the text below directly in vi as regular_express.txt file xff0c; xff0c; or fff0c; or xff1a, which is more directly recommended;

http://linux.vbird.org/linux_basic/0330regularex/regular_express.txt

如果你的 Linux 可以直接連上 Internet 的話,那麼使用如下的指令來捉取即可:

If your Linux can connect directly to the Internet & #xff0c; then use the following commands to capture & #xff1a;

wget http://linux.vbird.org/linux_basic/0330regularex/regular_express.txt

至於這個檔案的內容如下:

The contents of this file are as follows: #xff1a;

[root@www ~]# vi regular_express.txt
"Open Source" is a good mechanism to develop programs.
apple is my favorite food.
Football game is not use feet only.
this dress doesn't fit me.
However, this dress is about $ 3183 dollars.^M
GNU is free air not free beer.^M
Her hair is very beauty.^M
I can't finish the test.^M
Oh! The soup taste good.^M
motorcycle is cheap than car.
This window is clear.
the symbol '*' is represented as start.
Oh!     My god!
The gd software is a library for drafting programs.^M
You are the best is mean you are the no. 1.
The world <Happy> is the same with "glad".
I like dog.
google is the best tools for search keyword.
goooooogle yes!
go! go! Let's go.
# I am VBird

這檔案共有 22 行,最底下一行為空白行!現在開始我們一個案例一個案例的來介紹吧!

This file contains 22 lines & #xff0c; the bottom line is blank & #xff01; let's start with an introduction to a case in our case


  • 例題一、搜尋特定字串

搜尋特定字串很簡單吧?假設我們要從剛剛的檔案當中取得 the 這個特定字串,最簡單的方式就是這樣:

It's easy to search for a given string & #xff1f; let's assume we're going to get the specific string & #xff0c from the file; that's the simplest way to do it & #xff1a;

[root@www ~]# grep -n 'the' regular_express.txt
8:I can't finish the test.
12:the symbol '*' is represented as start.
15:You are the best is mean you are the no. 1.
16:The world <Happy> is the same with "glad".
18:google is the best tools for search keyword.

那如果想要『反向選擇』呢?也就是說,當該行沒有 'the' 這個字串時才顯示在螢幕上,那就直接使用:

What if xff1f; xff0c; 39; the39; 39; this string is only displayed on the screen xff0c; then xff1a;

[root@www ~]# grep -vn 'the' regular_express.txt

你會發現,螢幕上出現的行列為除了 8,12,15,16,18 五行之外的其他行列!接下來,如果你想要取得不論大小寫的 the 這個字串,則:

You'll find xff0c; the ranks on the screen are xff01; xff0c; xff0c; if you want to get the string xff0c; xff1a; xff1a;

[root@www ~]# grep -in 'the' regular_express.txt
8:I can't finish the test.
9:Oh! The soup taste good.
12:the symbol '*' is represented as start.
14:The gd software is a library for drafting programs.
15:You are the best is mean you are the no. 1.
16:The world <Happy> is the same with "glad".
18:google is the best tools for search keyword.

除了多兩行 (9, 14行) 之外,第 16 行也多了一個 The 的關鍵字被擷取到喔!

In addition to two more lines (9, 14 lines) xff0c; in line 16 there's another key to The xff01;


  • 例題二、利用中括號 [] 來搜尋集合字元

如果我想要搜尋 test 或 taste 這兩個單字時,可以發現到,其實她們有共通的 't?st'存在~這個時候,我可以這樣來搜尋:

If I want to search & #xff0c; & #xff0c; they have a common & #39; t?st#39; there & #xff5e; xff0c at this time; I can search #xff1a;

[root@www ~]# grep -n 't[ae]st' regular_express.txt
8:I can't finish the test.
9:Oh! The soup taste good.

瞭解了吧?其實 [] 裡面不論有幾個字元,他都謹代表某『一個』字元,所以,上面的例子說明了,我需要的字串是『tast』或『test』兩個字串而已!而如果想要搜尋到有 oo 的字元時,則使用:

See #xff1f; actually [] there are several characters & #xff0c; he represents a 'one' character & #xff0c; so #xff0c; the examples above indicate #xff0c; the string I need is #xff01; and #xff1a if you want to search for a oo character; #xff0c;

[root@www ~]# grep -n 'oo' regular_express.txt
1:"Open Source" is a good mechanism to develop programs.
2:apple is my favorite food.
3:Football game is not use feet only.
9:Oh! The soup taste good.
18:google is the best tools for search keyword.
19:goooooogle yes!

但是,如果我不想要 oo 前面有 g 的話呢?此時,可以利用在集合字元的反向選擇 [^] 來達成:

But xff0c; if I don't want oo with g in front xff1f; at this point xff0c; can use the reverse selection [] in the collective character to reach xff1a;

[root@www ~]# grep -n '[^g]oo' regular_express.txt
2:apple is my favorite food.
3:Football game is not use feet only.
18:google is the best tools for search keyword.
19:goooooogle yes!

意思就是說,我需要的是 oo ,但是 oo 前面不能是 g 就是了!仔細比較上面兩個表格,妳會發現,第 1,9 行不見了,因為 oo 前面出現了 g 所致!第 2,3 行沒有疑問,因為 foo 與 Foo 均可被接受!但是第 18 行明明有 google 的 goo 啊~別忘記了,因為該行後面出現了 tool 的 too 啊!所以該行也被列出來~也就是說, 18 行裡面雖然出現了我們所不要的項目 (goo) 但是由於有需要的項目 (too) ,因此,是符合字串搜尋的喔!

It means xff0c; what I need is xff0c; but oo can't go ahead is g or xff01; finely compare the two forms above xff0c; you'll find xff0c; line 1, 9 is missing xff0c; because oo appears in front of gff01; line 2, no questions xff0c; because foo and Foo can be accepted xfff01; line 18 has goo xff5e; don't forget xff0c; because tool xff01 appears behind that line; so the line is also listed xff5e; meaning xff0; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;

至於第 19 行,同樣的,因為 goooooogle 裡面的 oo 前面可能是 o ,例如:go(ooo)oogle ,所以,這一行也是符合需求的!

As for line 19 & #xff0c; the same xff0c; because oo in goooooogle may be in front of o & #xff0c; e. g. xff1a;go(oo)ogle & #xff0c; so xff0c; this line is also xff01;

再來,假設我 oo 前面不想要有小寫字元,所以,我可以這樣寫 [^abcd....z]oo ,但是這樣似乎不怎麼方便,由於小寫字元的 ASCII 上編碼的順序是連續的,因此,我們可以將之簡化為底下這樣:

xff0c; assuming I oo do not want lowercase characters xff0c; xff0c; so xff0c; I can write [abcd....z]oo & #xff0c; this does not seem convenient xff0c; the order of encoding on ASCII for lowercase characters is continuous xff0c; xff0c; thus xff0c; we can simplify it to xff1a below;

[root@www ~]# grep -n '[^a-z]oo' regular_express.txt
3:Football game is not use feet only.

也就是說,當我們在一組集合字元中,如果該字元組是連續的,例如大寫英文/小寫英文/數字等等,就可以使用[a-z],[A-Z],[0-9]等方式來書寫,那麼如果我們的要求字串是數字與英文呢?呵呵!就將他全部寫在一起,變成:[a-zA-Z0-9]。例如,我們要取得有數字的那一行,就這樣:

In other words, xff0c; when we're in a group of characters xff0c; if the character set is continuous xff0c; e.g. upper/lower English/digits, etc. xff0c; can be used to write xff0c, e.g., [a-z], [A-Z], [0-9]; then if we want the string to be numbers and English xff1f; huhxff01; if he is written all together xff0c; xff1a; [a-zA-Z0-9]. For example, xff0c; we have to get the line with numbers #xff0c; ff1a; so xff1a;

[root@www ~]# grep -n '[0-9]' regular_express.txt
5:However, this dress is about $ 3183 dollars.
15:You are the best is mean you are the no. 1.

但由於考慮到語系對於編碼順序的影響,因此除了連續編碼使用減號『 - 』之外,你也可以使用如下的方法來取得前面兩個測試的結果:

However, considering the influence of the language system on the coding order, xff0c; therefore xff0c, in addition to continuous encoding using minus sign xff0c; you can also use the following to obtain the results of the first two tests xff1a;

[root@www ~]# grep -n '[^[:lower:]]oo' regular_express.txt
# 那個 [:lower:] 代表的就是 a-z 的意思!請參考前兩小節的說明表格

[root@www ~]# grep -n '[[:digit:]]' regular_express.txt

這樣對於 [] 以及 [^] 以及 [] 當中的 - ,還有關於前面表格提到的特殊關鍵字有瞭解了嗎?^_^!

Does this make sense of any of the special keywords mentioned in the previous table? & & #xff0c; xff01;



  • 例題三、行首與行尾字元 ^ $

我們在例題一當中,可以查詢到一行字串裡面有 the 的,那如果我想要讓 the 只在行首列出呢?這個時候就得要使用定位字元了!我們可以這樣做:

xff0c; we can query the xff0c in a string; then if I want the name to be listed only at the beginning of the line, xff1f; this time we have to use the positioning character xff01; we can do this xff1a;

[root@www ~]# grep -n '^the' regular_express.txt
12:the symbol '*' is represented as start.

此時,就只剩下第 12 行,因為只有第 12 行的行首是 the 開頭啊~此外,如果我想要開頭是小寫字元的那一行就列出呢?可以這樣:

At this point #xff0c; only 12 lines & #xff0c; since the 12th line is headed by the beginning & #xff5e; and #xff0c; if I want to start with a lower writing character, the line is listed #xff1f; this way #xff1a;

[root@www ~]# grep -n '^[a-z]' regular_express.txt
2:apple is my favorite food.
4:this dress doesn't fit me.
10:motorcycle is cheap than car.
12:the symbol '*' is represented as start.
18:google is the best tools for search keyword.
19:goooooogle yes!
20:go! go! Let's go.

你可以發現我們可以捉到第一個字元都不是大寫的!只不過 grep 列出的關鍵字部分不只有第一個字元,grep 是列出一整個字 (word) 說!同樣的,上面的指令也可以用如下的方式來取代的:

You can see that we can catch the first character & #xff01 without capital; except that the grep lists more than the first character & #xff0c; grep lists the whole word & #xff01; the same xff0c; the above command can also replace xff1a in the following manner;

[root@www ~]# grep -n '^[[:lower:]]' regular_express.txt

好!那如果我不想要開頭是英文字母,則可以是這樣:

#xff01; if I don't want to start with the English letter #xff0c; this can be the case #xff1a;

[root@www ~]# grep -n '^[^a-zA-Z]' regular_express.txt
1:"Open Source" is a good mechanism to develop programs.
21:# I am VBird
# 指令也可以是: grep -n '^[^[:alpha:]]' regular_express.txt

注意到了吧?那個 ^ 符號,在字元集合符號(括號[])之內與之外是不同的!在 [] 內代表『反向選擇』,在 [] 之外則代表定位在行首的意義!要分清楚喔!反過來思考,那如果我想要找出來,行尾結束為小數點 (.) 的那一行,該如何處理:

Take note of #xff1f; the symbol & #xff0c; xff01 is different within and outside the character pool symbol (bracket[]; xff0c is represented within []; xff0c is represented outside

[root@www ~]# grep -n '\.$' regular_express.txt
1:"Open Source" is a good mechanism to develop programs.
2:apple is my favorite food.
3:Football game is not use feet only.
4:this dress doesn't fit me.
10:motorcycle is cheap than car.
11:This window is clear.
12:the symbol '*' is represented as start.
15:You are the best is mean you are the no. 1.
16:The world <Happy> is the same with "glad".
17:I like dog.
18:google is the best tools for search keyword.
20:go! go! Let's go.

特別注意到,因為小數點具有其他意義(底下會介紹),所以必須要使用跳脫字元(\)來加以解除其特殊意義!不過,你或許會覺得奇怪,但是第 5~9 行最後面也是 . 啊~怎麼無法列印出來?這裡就牽涉到 Windows 平台的軟體對於斷行字元的判斷問題了!我們使用 cat -A 將第五行拿出來看,你會發現:

Special attention is given to xff0c; because the decimal points have other meanings (presented below) xff0c; therefore, xff01 must be used to remove the special meaning of xff0c; but xff0c; you may find it strange xff0c; but the bottom of line 5-9 is also... xff5e; why xff1f cannot be printed; xff01 ; we use cat-A to show xff0c; you will find xff1a;

[root@www ~]# cat -An regular_express.txt | head -n 10 | tail -n 6
     5  However, this dress is about $ 3183 dollars.^M$
     6  GNU is free air not free beer.^M$
     7  Her hair is very beauty.^M$
     8  I can't finish the test.^M$
     9  Oh! The soup taste good.^M$
    10  motorcycle is cheap than car.$

我們在第十章內談到過斷行字元在 Linux 與 Windows 上的差異,在上面的表格中我們可以發現 5~9 行為 Windows 的斷行字元 (^M$) ,而正常的 Linux 應該僅有第 10 行顯示的那樣 ($)。所以囉,那個 . 自然就不是緊接在 $ 之前喔!也就捉不到 5~9 行了!這樣可以瞭解 ^ 與 $ 的意義嗎?好了,先不要看底下的解答,自己想一想,那麼如果我想要找出來,哪一行是『空白行』,也就是說,該行並沒有輸入任何資料,該如何搜尋?

In chapter we talked about the breakword on Linux and Windows xff0c; in the form above we can find the breakwords of 5-9 lines Windows (M$) & #xff0c; x x x x x x x x x x x x ff #0 x x x x x x x x x x x x x x #ff #0 x x x x x x x x x x ff #f x x x x x x ff #f x x x x x x x ff x x x x x x x x x x x x x x x x x x x ff x x x x x x x x x x x x x ff x x x x x x x x x x x x x x x x x ff x x x x x x x x x x x x x x x x x x x x x x x x x x x ff x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x ff ff ff ff ff ff x x x x x x x x x x x ff ff ff ff ff ff x x x x x x x x x x x x x x x x x x x x x ff ff ff ff ff ff ff ff x x x x x x x x x x x x x x x x x x x x x x ff ff ff ff ff ff ff ff x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x ff ff

[root@www ~]# grep -n '^$' regular_express.txt
22:

因為只有行首跟行尾 (^$),所以,這樣就可以找出空白行啦!再來,假設你已經知道在一個程式腳本(shell script) 或者是設定檔當中,空白行與開頭為 # 的那一行是註解,因此如果你要將資料列出給別人參考時,可以將這些資料省略掉以節省保貴的紙張,那麼你可以怎麼作呢?我們以 /etc/syslog.conf 這個檔案來作範例,你可以自行參考一下輸出的結果:

Because only the line header ($) & #xff0c; so xff0c; so you can find blank lines xff01; xff0c; assuming you already know what you're doing in a program script (shell Script) or in a configuration file xff0c; the line with blank lines and openings # is comment xff0c; so if you want to list the data for someone else xff0c; you can delete the data to save xff0c; then how can you do it? xff1f; we use the file /etc/syslog.conf for example #xff0c; you can look at the results of your own output xff1a;

[root@www ~]# cat -n /etc/syslog.conf
# 在 CentOS 中,結果可以發現有 33 行的輸出,很多空白行與 # 開頭

[root@www ~]# grep -v '^$' /etc/syslog.conf | grep -v '^#'
# 結果僅有 10 行,其中第一個『 -v '^$' 』代表『不要空白行』,
# 第二個『 -v '^#' 』代表『不要開頭是 # 的那行』喔!

是否節省很多版面啊?

#xff1f;



  • 例題四、任意一個字元 . 與重複字元 *

第十一章 bash 當中,我們知道萬用字元 * 可以用來代表任意(0或多個)字元,但是正規表示法並不是萬用字元,兩者之間是不相同的!至於正規表示法當中的『 . 』則代表『絕對有一個任意字元』的意思!這兩個符號在正規表示法的意義如下:

In chapter XI of xff0c; we know that can be used to represent arbitrary (0 or more) phrases xff0c; however, ; and #ff #1 s not a valid sign of #01 xxxxxx ff

這樣講不好懂,我們直接做個練習吧!假設我需要找出 gd 的字串,亦即共有四個字元,起頭是 g 而結束是 d ,我可以這樣做:

It's hard to understand #xff0c; let's just practice #xff01; assuming I need to find gd's string xff0c; that's four characters xff0c; starting with g and ending with d & #xff0c; I can do this #xff1a;

[root@www ~]# grep -n 'g..d' regular_express.txt
1:"Open Source" is a good mechanism to develop programs.
9:Oh! The soup taste good.
16:The world <Happy> is the same with "glad".

因為強調 g 與 d 之間一定要存在兩個字元,因此,第 13 行的 god 與第 14 行的 gd 就不會被列出來啦!再來,如果我想要列出有 oo, ooo, oooo 等等的資料,也就是說,至少要有兩個(含) o 以上,該如何是好?是 o* 還是 oo* 還是 ooo* 呢?雖然你可以試看看結果, 不過結果太佔版面了 @_@ ,所以,我這裡就直接說明。

Because it is important to stress that there must be two characters between g and d & #xff0c; therefore & #xff0c; god and gd in line 13 & 14 & #xff01; & #xff0c; if I want to list oo, oo, oo, oo, etc. & #xff0c; i.e. #xff0c; at least two #xff0c; how #xff1f; o* oo* or oo*

因為 * 代表的是『重複 0 個或多個前面的 RE 字符』的意義,因此,『o*』代表的是:『擁有空字元或一個 o 以上的字元』,特別注意,因為允許空字元(就是有沒有字元都可以的意思),因此,『 grep -n 'o*' regular_express.txt 』將會把所有的資料都列印出來螢幕上!

* For the meaning of xff0c; xff0c; span_text_import2'; xff1a; span_text_import2'; spanxff0c; xff0c; span_text_import2'o*; spanxff0c; xff0c; xff0c; spans= "text_import2" >grep-n & #39; 39; regular_express.txt); xff01;

那如果是『oo*』呢?則第一個 o 肯定必須要存在,第二個 o 則是可有可無的多個 o ,所以,凡是含有 o, oo, ooo, oooo 等等,都可以被列出來~

If "oo" then #xff1f; the first o must exist xff0c; the second o is the number of unattainable o & #xff0c; so xff0c; anything containing o, oo, oo, oooo et al. xff0c; all can be listed xff5e;

同理,當我們需要『至少兩個 o 以上的字串』時,就需要 ooo* ,亦即是:

#xff0c; #xff0c when we need 'at least two or more strings'; #oo* & #xff0c; i. e. xff1a;

[root@www ~]# grep -n 'ooo*' regular_express.txt
1:"Open Source" is a good mechanism to develop programs.
2:apple is my favorite food.
3:Football game is not use feet only.
9:Oh! The soup taste good.
18:google is the best tools for search keyword.
19:goooooogle yes!

這樣理解 * 的意義了嗎?好了,現在出個練習,如果我想要字串開頭與結尾都是 g,但是兩個 g 之間僅能存在至少一個 o ,亦即是 gog, goog, gooog.... 等等,那該如何?

Is that the meaning of *? #xff1f; #xff0c; now practice #xff0c; if I want the string to start and end with g#xff0c; but only at least one o & #xff0c; that is gog, goog, gooog... et cetera #xff0c; how #xff1f;

[root@www ~]# grep -n 'goo*g' regular_express.txt
18:google is the best tools for search keyword.
19:goooooogle yes!

如此瞭解了嗎?再來一題,如果我想要找出 g 開頭與 g 結尾的字串,當中的字元可有可無,那該如何是好?是『g*g』嗎?

Is that so? #xff1f; one more question #xff0c; if I want to find the string g at the beginning and g at the end #xff0c; if there's no #xff0c in the character; what's good #xff1f;'g*g'? #xff1f;

[root@www ~]# grep -n 'g*g' regular_express.txt
1:"Open Source" is a good mechanism to develop programs.
3:Football game is not use feet only.
9:Oh! The soup taste good.
13:Oh!  My god!
14:The gd software is a library for drafting programs.
16:The world <Happy> is the same with "glad".
17:I like dog.
18:google is the best tools for search keyword.
19:goooooogle yes!
20:go! go! Let's go.

但測試的結果竟然出現這麼多行?太詭異了吧?其實一點也不詭異,因為 g*g 裡面的 g* 代表『空字元或一個以上的 g』在加上後面的 g ,因此,整個 RE 的內容就是 g, gg, ggg, gggg ,因此,只要該行當中擁有一個以上的 g 就符合所需了!

But the results of the test show so many lines xff1f; xff1f; it's not really weird xff0c; it's because g* in g*g stands for g & #xff0c at the end of `space character or more'; xff0c; thus re, gg, ggg, gg & #xff0c; xff0c; so xff0c; as long as there is more than one g in the line, it meets the required xff01;

那該如何得到我們的 g....g 的需求呢?呵呵!就利用任意一個字元『.』啊!亦即是:『g.*g』的作法,因為 * 可以是 0 或多個重複前面的字符,而 . 是任意字元,所以:『.* 就代表零個或多個任意字元』的意思啦!

How do we get our g.....g. needs?.......................................................................................................

[root@www ~]# grep -n 'g.*g' regular_express.txt
1:"Open Source" is a good mechanism to develop programs.
14:The gd software is a library for drafting programs.
18:google is the best tools for search keyword.
19:goooooogle yes!
20:go! go! Let's go.

因為是代表 g 開頭與 g 結尾,中間任意字元均可接受,所以,第 1, 14, 20 行是可接受的喔!這個 .* 的 RE 表示任意字元是很常見的,希望大家能夠理解並且熟悉!再出一題,如果我想要找出『任意數字』的行列呢?因為僅有數字,所以就成為:

Because it represents g at the beginning and g end of xff0c; xff0c; therefore xff0c; No. 1, 14, 20 rows are acceptable xff01; this... * RE indicates that arbitrary characters are common xff0c; want to be understood and familiar with xff01; issue xff0c; xff1f; become xff1a if I want to find any number; xff0c; xff1a;

[root@www ~]# grep -n '[0-9][0-9]*' regular_express.txt
5:However, this dress is about $ 3183 dollars.
15:You are the best is mean you are the no. 1.

雖然使用 grep -n '[0-9]' regular_express.txt 也可以得到相同的結果,但鳥哥希望大家能夠理解上面指令當中 RE 表示法的意義才好!

Although the same result can be obtained using grep-n & #39; [0-9] & #39; regular_express.txt; however, Brother Bird wants you to understand the meaning of the RE expression in the above command


  • 例題五、限定連續 RE 字符範圍 {}

在上個例題當中,我們可以利用 . 與 RE 字符及 * 來設定 0 個到無限多個重複字元,那如果我想要限制一個範圍區間內的重複字元數呢?舉例來說,我想要找出兩個到五個 o 的連續字串,該如何作?這時候就得要使用到限定範圍的字符 {} 了。但因為 { 與 } 的符號在 shell 是有特殊意義的,因此,我們必須要使用跳脫字符 \ 來讓他失去特殊意義才行。至於 {} 的語法是這樣的,假設我要找到兩個 o 的字串,可以是:

In the previous case, xff0c; we can use... and RE characters and * to set 0 to an unlimited number of duplicate characters xff0c; if I want to limit the number of duplicate characters in a range, xff1f; for example, xff0c; I want to find two to five xff0c; how to do xff1f; this time to use spans="text_import2" because the symbol {and} has a special meaning xff0c; thus xff0c; we have to use a jump to make him lose special meaning. to ;

[root@www ~]# grep -n 'o\{2\}' regular_express.txt
1:"Open Source" is a good mechanism to develop programs.
2:apple is my favorite food.
3:Football game is not use feet only.
9:Oh! The soup taste good.
18:google is the best tools for search keyword.
19:goooooogle yes!

這樣看似乎與 ooo* 的字符沒有什麼差異啊?因為第 19 行有多個 o 依舊也出現了!好,那麼換個搜尋的字串,假設我們要找出 g 後面接 2 到 5 個 o ,然後再接一個 g 的字串,他會是這樣:

This does not seem to make any difference with the oo* character & #xff1f; because the 19th line also appears in #xff01; good #xff0c; then the search string & #xff0c; assuming we're going to find g behind 2 to 5 o & #xff0c; then we're going to add a g string #xff0c; he's going to be like #xff1a;

[root@www ~]# grep -n 'go\{2,5\}g' regular_express.txt
18:google is the best tools for search keyword.

嗯!很好!第 19 行終於沒有被取用了(因為 19 行有 6 個 o 啊!)。那麼,如果我想要的是 2 個 o 以上的 goooo....g 呢?除了可以是 gooo*g ,也可以是:

Hm #xff01; good #xff01; 19th line is not finally taken (because there are 6 o & #xff01;). So #xff0c; #xff1f if I want 2 or more gooo... & xff1f; except that it can be gooo*g & #xff0c; #xff1a;

[root@www ~]# grep -n 'go\{2,\}g' regular_express.txt
18:google is the best tools for search keyword.
19:goooooogle yes!

呵呵!就可以找出來啦~

Oh, #xff01; you can find it #xff5e;


小標題的圖示 基礎正規表示法字符彙整(characters)

經過了上面的幾個簡單的範例,我們可以將基礎的正規表示法特殊字符彙整如下:

After a few simple examples above xff0c; we can encapsulate the underlying regular expression special characters as xff1a;

RE 字符意義與範例
^word意義:待搜尋的字串(word)在行首!
範例:搜尋行首為 # 開始的那一行,並列出行號
grep -n '^#' regular_express.txt
word$意義:待搜尋的字串(word)在行尾!
範例:將行尾為 ! 的那一行列印出來,並列出行號
grep -n '!$' regular_express.txt
.意義:代表『一定有一個任意字元』的字符!
範例:搜尋的字串可以是 (eve) (eae) (eee) (e e), 但不能僅有 (ee) !亦即 e 與 e 中間『一定』僅有一個字元,而空白字元也是字元!
grep -n 'e.e' regular_express.txt
\意義:跳脫字符,將特殊符號的特殊意義去除!
範例:搜尋含有單引號 ' 的那一行!
grep -n \' regular_express.txt
*意義:重複零個到無窮多個的前一個 RE 字符
範例:找出含有 (es) (ess) (esss) 等等的字串,注意,因為 * 可以是 0 個,所以 es 也是符合帶搜尋字串。另外,因為 * 為重複『前一個 RE 字符』的符號, 因此,在 * 之前必須要緊接著一個 RE 字符喔!例如任意字元則為 『.*』 !
grep -n 'ess*' regular_express.txt
[list]意義:字元集合的 RE 字符,裡面列出想要擷取的字元!
範例:搜尋含有 (gl) 或 (gd) 的那一行,需要特別留意的是,在 [] 當中『謹代表一個待搜尋的字元』,例如『 a[afl]y 』代表搜尋的字串可以是 aay, afy, aly 即 [afl] 代表 a 或 f 或 l 的意思!
grep -n 'g[ld]' regular_express.txt
[n1-n2]意義:字元集合的 RE 字符,裡面列出想要擷取的字元範圍!
範例:搜尋含有任意數字的那一行!需特別留意,在字元集合 [] 中的減號 - 是有特殊意義的,他代表兩個字元之間的所有連續字元!但這個連續與否與 ASCII 編碼有關,因此,你的編碼需要設定正確(在 bash 當中,需要確定 LANG 與 LANGUAGE 的變數是否正確!) 例如所有大寫字元則為 [A-Z]
grep -n '[A-Z]' regular_express.txt
[^list]意義:字元集合的 RE 字符,裡面列出不要的字串或範圍!
範例:搜尋的字串可以是 (oog) (ood) 但不能是 (oot) ,那個 ^ 在 [] 內時,代表的意義是『反向選擇』的意思。例如,我不要大寫字元,則為 [^A-Z]。但是,需要特別注意的是,如果以 grep -n [^A-Z] regular_express.txt 來搜尋,卻發現該檔案內的所有行都被列出,為什麼?因為這個 [^A-Z] 是『非大寫字元』的意思,因為每一行均有非大寫字元,例如第一行的 "Open Source" 就有 p,e,n,o.... 等等的小寫字
grep -n 'oo[^t]' regular_express.txt
\{n,m\}意義:連續 n 到 m 個的『前一個 RE 字符』
意義:若為 \{n\} 則是連續 n 個的前一個 RE 字符,
意義:若是 \{n,\} 則是連續 n 個以上的前一個 RE 字符!
範例:在 g 與 g 之間有 2 個到 3 個的 o 存在的字串,亦即 (goog)(gooog)
grep -n 'go\{2,3\}g' regular_express.txt

再次強調:『正規表示法的特殊字元』與一般在指令列輸入指令的『萬用字元』並不相同,例如,在萬用字元當中的 * 代表的是『 0 ~ 無限多個字元』的意思,但是在正規表示法當中,* 則是『重複 0 到無窮多個的前一個 RE 字符』的意思~使用的意義並不相同,不要搞混了!

Re-emphasize that xff1a; ' ls | grep -n '^a.*'

例題:
以 ls -l 配合 grep 找出 /etc/ 底下檔案類型為連結檔屬性的檔名
答:
由於 ls -l 列出連結檔時標頭會是『 lrwxrwxrwx 』,因此使用如下的指令即可找出結果:
ls -l /etc | grep '^l'
若僅想要列出幾個檔案,再以『 |wc -l 』 來累加處理即可。


小標題的圖示 sed 工具

在瞭解了一些正規表示法的基礎應用之後,再來呢?呵呵~兩個東西可以玩一玩的,那就是 sed 跟底下會介紹的 awk 了!這兩個傢伙可是相當的有用的啊!舉例來說,鳥哥寫的 logfile.sh 分析登錄檔的小程式(第十九章會談到),絕大部分分析關鍵字的取用、統計等等,就是用這兩個寶貝蛋來幫我完成的!那麼你說,要不要玩一玩啊?^_^

xff0c; xfff; fff; xff5e; xff0c; xk; xff0c; k xff01; xff01; xff01; txff0c; target=hrek'href=http://linux.vbird.org/linux_basic/0570slog.php'rel="nosollowernoreferrer'>logfile.sh; for example, xff0c); xfff0c; xxxxxxxx; fxfx; fxxxxxx; fxxxxxf;

我們先來談一談 sed 好了, sed 本身也是一個管線命令,可以分析 standard input 的啦!而且 sed 還可以將資料進行取代、刪除、新增、擷取特定行等等的功能呢!很不錯吧~我們先來瞭解一下 sed 的用法,再來聊他的用途好了!

Let's talk about sed & #xff0c; sed is itself a piped command & #xff0c; sed can analyze standard input & #xff01; and sed can replace, delete, add, grab specific lines and so on #xff01; #xff5e; let's get to know how sed works & #xff0c; and talk about his use #xff01;

[root@www ~]# sed [-nefr] [動作]
選項與參數:
-n  :使用安靜(silent)模式。在一般 sed 的用法中,所有來自 STDIN 
      的資料一般都會被列出到螢幕上。但如果加上 -n 參數後,則只有經過
      sed 特殊處理的那一行(或者動作)才會被列出來。
-e  :直接在指令列模式上進行 sed 的動作編輯;
-f  :直接將 sed 的動作寫在一個檔案內, -f filename 則可以執行 filename 內的 
      sed 動作;
-r  :sed 的動作支援的是延伸型正規表示法的語法。(預設是基礎正規表示法語法)
-i  :直接修改讀取的檔案內容,而不是由螢幕輸出。

動作說明:  [n1[,n2]]function
n1, n2 :不見得會存在,一般代表『選擇進行動作的行數』,舉例來說,如果我的動作
         是需要在 10 到 20 行之間進行的,則『 10,20[動作行為] 』

function 有底下這些咚咚:
a   :新增, a 的後面可以接字串,而這些字串會在新的一行出現(目前的下一行)~
c   :取代, c 的後面可以接字串,這些字串可以取代 n1,n2 之間的行!
d   :刪除,因為是刪除啊,所以 d 後面通常不接任何咚咚;
i   :插入, i 的後面可以接字串,而這些字串會在新的一行出現(目前的上一行);
p   :列印,亦即將某個選擇的資料印出。通常 p 會與參數 sed -n 一起運作~
s   :取代,可以直接進行取代的工作哩!通常這個 s 的動作可以搭配
      正規表示法!例如 1,20s/old/new/g 就是啦!

  • 以行為單位的新增/刪除功能

sed 光是用看的是看不懂的啦!所以又要來練習了!先來玩玩刪除與新增的功能吧!

#xff01; so it's time to practice #xff01; play with delete and add functions #xff01;

範例一:將 /etc/passwd 的內容列出並且列印行號,同時,請將第 2~5 行刪除!
[root@www ~]# nl /etc/passwd | sed '2,5d'
     1  root:x:0:0:root:/root:/bin/bash
     6  sync:x:5:0:sync:/sbin:/bin/sync
     7  shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
.....(後面省略).....

看到了吧?sed 的動作為 '2,5d' ,那個 d 就是刪除!因為 2-5 行給他刪除了,所以顯示的資料就沒有 2-5 行囉~另外,注意一下,原本應該是要下達 sed -e 才對,沒有 -e 也行啦!同時也要注意的是, sed 後面接的動作,請務必以 '' 兩個單引號括住喔!

See & #xff1f; sed for action & #39; 2,5d' & #xff0c; d for ! because 2-5 line deleted & #xff0c; so the data shown is not 2-5 lines & #xff5e; & #xff0c; also & #xff0c; & #xff0c; originally meant to be sed-e for #xff0c; no-e plus #xff01; & #xff0c; sed behind & #xff0c; & #39; two single quotes covering #xff01;

如果題型變化一下,舉例來說,如果只要刪除第 2 行,可以使用『 nl /etc/passwd | sed '2d' 』來達成,至於若是要刪除第 3 到最後一行,則是『 nl /etc/passwd | sed '3,$d' 』的啦,那個錢字號『 $ 』代表最後一行!

If the theme changes xff0c; for example xff0c; if line 2 is deleted xff0c; if line 2 is deleted xff0c; you can use 'nl/etc/passwdsed & #39; 2d' 'to xff0c; if you delete line 3 to last line xff0c; if you delete line nl/etc/passwdsed & #39; 3,$d#39;'

範例二:承上題,在第二行後(亦即是加在第三行)加上『drink tea?』字樣!
[root@www ~]# nl /etc/passwd | sed '2a drink tea'
     1  root:x:0:0:root:/root:/bin/bash
     2  bin:x:1:1:bin:/bin:/sbin/nologin
drink tea
     3  daemon:x:2:2:daemon:/sbin:/sbin/nologin
.....(後面省略).....

嘿嘿!在 a 後面加上的字串就已將出現在第二行後面囉!那如果是要在第二行前呢?『nl /etc/passwd | sed '2i drink tea' 』就對啦!就是將『 a 』變成『 i 』即可。增加一行很簡單,那如果是要增將兩行以上呢?

Hey #xff01; the string added behind a line is xff01; xff01; xff1f; nl/etc/passwd sed & #39; drink tea' xff01; that's a i; xff0c; xff1f; xff1f;

範例三:在第二行後面加入兩行字,例如『Drink tea or .....』與『drink beer?』
[root@www ~]# nl /etc/passwd | sed '2a Drink tea or ......\
> drink beer ?'
     1  root:x:0:0:root:/root:/bin/bash
     2  bin:x:1:1:bin:/bin:/sbin/nologin
Drink tea or ......
drink beer ?
     3  daemon:x:2:2:daemon:/sbin:/sbin/nologin
.....(後面省略).....

這個範例的重點是『我們可以新增不只一行喔!可以新增好幾行』但是每一行之間都必須要以反斜線『 \ 』來進行新行的增加喔!所以,上面的例子中,我們可以發現在第一行的最後面就有 \ 存在啦!那是一定要的喔!

The point of this example is that "We can add more than one line #xff01; we can add several lines", but each line has to add a new line in reverse xff01; so xff0c; in the above example xff0c; we can find that there is xff01 at the end of the first line; that is xff01;



  • 以行為單位的取代與顯示功能

剛剛是介紹如何新增與刪除,那麼如果要整行取代呢?看看底下的範例吧:

Just introduced how to add and delete #xff0c; then what if the whole line were to replace #xff1f; look at the example below #xff1a;

範例四:我想將第2-5行的內容取代成為『No 2-5 number』呢?
[root@www ~]# nl /etc/passwd | sed '2,5c No 2-5 number'
     1  root:x:0:0:root:/root:/bin/bash
No 2-5 number
     6  sync:x:5:0:sync:/sbin:/bin/sync
.....(後面省略).....

透過這個方法我們就能夠將資料整行取代了!非常容易吧!sed 還有更好用的東東!我們以前想要列出第 11~20 行,得要透過『head -n 20 | tail -n 10』之類的方法來處理,很麻煩啦~sed 則可以簡單的直接取出你想要的那幾行!是透過行號來捉的喔!看看底下的範例先:

Through this method, we can replace xff01 with data lines; very easy xff01; sed and better used xff01; we used to list lines 11~20 xff0c; we have to deal with xff0c through head-n-20 tail-n10; it's troublesome xff5e; sed can simply take out the lines xff01; it's captured by pass sign #xff01; look at the example below ff1a;

範例五:僅列出 /etc/passwd 檔案內的第 5-7 行
[root@www ~]# nl /etc/passwd | sed -n '5,7p'
     5  lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
     6  sync:x:5:0:sync:/sbin:/bin/sync
     7  shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

上述的指令中有個重要的選項『 -n 』,按照說明文件,這個 -n 代表的是『安靜模式』!那麼為什麼要使用安靜模式呢?你可以自行下達 sed '5,7p' 就知道了 (5-7 行會重複輸出)!有沒有加上 -n 的參數時,輸出的資料可是差很多的喔!你可以透過這個 sed 的以行為單位的顯示功能,就能夠將某一個檔案內的某些行號捉出來查閱!很棒的功能!不是嗎?

An important option in the above-mentioned instructions is '-n' & #xff0c; this -n represents `silent mode' & #xff01; then why do you use quiet mode & #xff1f; you can use sed & #39; 5,7p #39; you know that (5-7 lines repeat #ff01; #xff01; xff0c); you add -n parameters & fff; the data are very different #xff01; you can access this sed #xff0c; you can capture certain lines in a file #xff01; #xff01; it's great #ff1f;

> >.


  • 部分資料的搜尋並取代的功能

除了整行的處理模式之外, sed 還可以用行為單位進行部分資料的搜尋並取代的功能喔!基本上 sed 的搜尋與取代的與 vi 相當的類似!他有點像這樣:

xff0c; sed can also use behavioral units to search for part of the data and replace it xff01; basically sed searches and replaces similar to vi xff01; he's kind of like xff1a;

sed 's/要被取代的字串/新的字串/g'

上表中特殊字體的部分為關鍵字,請記下來!至於三個斜線分成兩欄就是新舊字串的替換啦!我們使用底下這個取得 IP 數據的範例,一段一段的來處理給您瞧瞧,讓你瞭解一下什麼是咱們所謂的搜尋並取代吧!

The part of the special font in the above table is the key & #xff0c; please note & #xff01; as for the three slants, the replacement of the old & #xff01; we use the example below to get IP data & #xff0c; a paragraph to show you #xff0c; let you understand what we call search and replace #xff01;

步驟一:先觀察原始訊息,利用 /sbin/ifconfig  查詢 IP 為何?
[root@www ~]# /sbin/ifconfig eth0
eth0      Link encap:Ethernet  HWaddr 00:90:CC:A6:34:84
          inet addr:192.168.1.100  Bcast:192.168.1.255  Mask:255.255.255.0
          inet6 addr: fe80::290:ccff:fea6:3484/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
.....(以下省略).....
# 因為我們還沒有講到 IP ,這裡你先有個概念即可啊!我們的重點在第二行,
# 也就是 192.168.1.100 那一行而已!先利用關鍵字捉出那一行!

步驟二:利用關鍵字配合 grep 擷取出關鍵的一行資料
[root@www ~]# /sbin/ifconfig eth0 | grep 'inet addr'
          inet addr:192.168.1.100  Bcast:192.168.1.255  Mask:255.255.255.0
# 當場僅剩下一行!接下來,我們要將開始到 addr: 通通刪除,就是像底下這樣:
# inet addr:192.168.1.100  Bcast:192.168.1.255  Mask:255.255.255.0
# 上面的刪除關鍵在於『 ^.*inet addr: 』啦!正規表示法出現! ^_^

步驟三:將 IP 前面的部分予以刪除
[root@www ~]# /sbin/ifconfig eth0 | grep 'inet addr' | \
>  sed 's/^.*addr://g'
192.168.1.100  Bcast:192.168.1.255  Mask:255.255.255.0
# 仔細與上個步驟比較一下,前面的部分不見了!接下來則是刪除後續的部分,亦即:
# 192.168.1.100  Bcast:192.168.1.255  Mask:255.255.255.0
# 此時所需的正規表示法為:『 Bcast.*$ 』就是啦!

步驟四:將 IP 後面的部分予以刪除
[root@www ~]# /sbin/ifconfig eth0 | grep 'inet addr' | \
>  sed 's/^.*addr://g' | sed 's/Bcast.*$//g'
192.168.1.100

透過這個範例的練習也建議您依據此一步驟來研究你的指令!就是先觀察,然後再一層一層的試做,如果有做不對的地方,就先予以修改,改完之後測試,成功後再往下繼續測試。以鳥哥上面的介紹中,那一大串指令就做了四個步驟!對吧! ^_^

Through this example, it is also recommended that you study your instructions & #xff01; observe & #xff0c first; then try & #xff0c on one floor; modify & #xff0c first if there is something wrong; test & #xff0c after change; test #xff0c after success; then continue down.

讓我們再來繼續研究 sed 與正規表示法的配合練習!假設我只要 MAN 存在的那幾行資料,但是含有 # 在內的註解我不想要,而且空白行我也不要!此時該如何處理呢?可以透過這幾個步驟來實作看看:

Let's go back to sed and the combination of regular expressions & #xff01; let's assume that all I need is MAN's existence & #xff0c; but I don't want #xff0c; I don't want #xff01; I don't want #xff1; what to do at this time #xff1f; I can see through these steps #xff1a;

步驟一:先使用 grep 將關鍵字 MAN 所在行取出來
[root@www ~]# cat /etc/man.config | grep 'MAN'
# when MANPATH contains an empty substring), to find out where the cat
# MANBIN                pathname
# MANPATH               manpath_element [corresponding_catdir]
# MANPATH_MAP           path_element    manpath_element
# MANBIN                /usr/local/bin/man
# Every automatically generated MANPATH includes these fields
MANPATH /usr/man
....(後面省略)....

步驟二:刪除掉註解之後的資料!
[root@www ~]# cat /etc/man.config | grep 'MAN'| sed 's/#.*$//g'






MANPATH /usr/man
....(後面省略)....
# 從上面可以看出來,原本註解的資料都變成空白行啦!所以,接下來要刪除掉空白行

[root@www ~]# cat /etc/man.config | grep 'MAN'| sed 's/#.*$//g' | \
> sed '/^$/d'
MANPATH /usr/man
MANPATH /usr/share/man
MANPATH /usr/local/man
....(後面省略)....

  • 直接修改檔案內容(危險動作)

你以為 sed 只有這樣的能耐嗎?那可不! sed 甚至可以直接修改檔案的內容呢!而不必使用管線命令或資料流重導向!不過,由於這個動作會直接修改到原始的檔案,所以請你千萬不要隨便拿系統設定檔來測試喔!我們還是使用你下載的 regular_express.txt 檔案來測試看看吧!

You think that's all you can do? #xff1f; that's not #xff01; that's even direct modification of the file's contents & #xff01; instead of re-directing to #xff01 using a piped command or data stream; & #xff0c; because this action directly changes to the original file & #xff0c; so don't just try with the system configuration file & #xff01; let's test it with your downloaded regular_express.txt files; #xff01;

範例六:利用 sed 將 regular_express.txt 內每一行結尾若為 . 則換成 !
[root@www ~]# sed -i 's/\.$/\!/g' regular_express.txt
# 上頭的 -i 選項可以讓你的 sed 直接去修改後面接的檔案內容而不是由螢幕輸出喔!
# 這個範例是用在取代!請您自行 cat 該檔案去查閱結果囉!

範例七:利用 sed 直接在 regular_express.txt 最後一行加入『# This is a test』
[root@www ~]# sed -i '$a # This is a test' regular_express.txt
# 由於 $ 代表的是最後一行,而 a 的動作是新增,因此該檔案最後新增囉!

sed 的『 -i 』選項可以直接修改檔案內容,這功能非常有幫助!舉例來說,如果你有一個 100 萬行的檔案,你要在第 100 行加某些文字,此時使用 vim 可能會瘋掉!因為檔案太大了!那怎辦?就利用 sed 啊!透過 sed 直接修改/取代的功能,你甚至不需要使用 vim 去修訂!很棒吧!

The '-i'option for sed can directly modify the file content xff0c; this function is very helpful xff01; xff0c for example; if you have a million-line file xff0c; if you want to add some text xff0c to line 100; if you use the vim at this time xff01; because the file is too big xff01; xff1f; use the sed xff01; use the sed xff01; directly modify/replace functions xff0c; you don't even need to use the vim to fix xff01; it's great #xff01;

總之,這個 sed 不錯用啦!而且很多的 shell script 都會使用到這個指令的功能~sed 可以幫助系統管理員管理好日常的工作喔!要仔細的學習呢!

Anyway, #xff0c; this sed works well & #xff01; and many shell scripts use this command & #xff5e; sed helps system administrators manage their day-to-day work #xff01; learn carefully #xff01;


大標題的圖示延伸正規表示法

事實上,一般讀者只要瞭解基礎型的正規表示法大概就已經相當足夠了,不過,某些時刻為了要簡化整個指令操作,瞭解一下使用範圍更廣的延伸型正規表示法的表示式會更方便呢!舉個簡單的例子好了,在上節的例題三的最後一個例子中,我們要去除空白行與行首為 # 的行列,使用的是

In fact, xff0c; the general reader's knowledge of the underlying formal expressions is probably enough xff0c; xff0c; however, xff0c; some moments to simplify the whole command operation ff0c; it would be easier to understand the expression of the more extensive extended formal expression xff01; a simple example xff0c; the last example of ; we have to remove the blank lines and lines of #xff0c; it is used by #xff0c;

grep -v '^$' regular_express.txt | grep -v '^#'

需要使用到管線命令來搜尋兩次!那麼如果使用延伸型的正規表示法,我們可以簡化為:

A pipe command is required to search twice for xff01; if an extended regular expression is used xff0c; we can simplify it to xff1a;

egrep -v '^$|^#' regular_express.txt

延伸型正規表示法可以透過群組功能『 | 』來進行一次搜尋!那個在單引號內的管線意義為『或 or』啦!是否變的更簡單呢?此外,grep 預設僅支援基礎正規表示法,如果要使用延伸型正規表示法,你可以使用 grep -E ,不過更建議直接使用 egrep !直接區分指令比較好記憶!其實 egrep 與 grep -E 是類似命令別名的關係啦!

Extended regular means allow for a search through group function 'xff01; the line in single quotes means 'or'#xff01; whether it changes easier xff1f; and xff0c; grep default only supports the base rule expression xff0c; if extension regulars are used xff0c; you can use grep-E & #xff0c; but it is more advisable to use egrep & #xff01 directly; direct subdirection commands are better memory #xff01; whereas egrep and grep-E are similar command alias #xff01;

熟悉了正規表示法之後,到這個延伸型的正規表示法,你應該也會想到,不就是多幾個重要的特殊符號嗎? ^_^y 是的~所以,我們就直接來說明一下,延伸型正規表示法有哪幾個特殊符號?由於底下的範例還是有使用到 regular_express.txt,不巧的是剛剛我們可能將該檔案修改過了 @_@,所以,請重新下載該檔案來練習喔!

xff0c; xff0c; xff0c; you should also think of xff0c; y xff5e; xff0c; xff0c; xy xff0c; xff0c; xff1f; xff1f; use of regular_express.txt, from the example below; unfortunately, we may have just modified the file 64; 64; xff0c; xff0c; so xff0c; please reload the file to practice xff01;

RE 字符意義與範例
+意義:重複『一個或一個以上』的前一個 RE 字符
範例:搜尋 (god) (good) (goood)... 等等的字串。 那個 o+ 代表『一個以上的 o 』所以,底下的執行成果會將第 1, 9, 13 行列出來。
egrep -n 'go+d' regular_express.txt
?意義:『零個或一個』的前一個 RE 字符
範例:搜尋 (gd) (god) 這兩個字串。 那個 o? 代表『空的或 1 個 o 』所以,上面的執行成果會將第 13, 14 行列出來。有沒有發現到,這兩個案例( 'go+d' 與 'go?d' )的結果集合與 'go*d' 相同? 想想看,這是為什麼喔! ^_^
egrep -n 'go?d' regular_express.txt
|意義:用或( or )的方式找出數個字串
範例:搜尋 gd 或 good 這兩個字串,注意,是『或』! 所以,第 1,9,14 這三行都可以被列印出來喔!那如果還想要找出 dog 呢?
egrep -n 'gd|good' regular_express.txt
egrep -n 'gd|good|dog' regular_express.txt
()意義:找出『群組』字串
範例:搜尋 (glad) 或 (good) 這兩個字串,因為 g 與 d 是重複的,所以, 我就可以將 la 與 oo 列於 ( ) 當中,並以 | 來分隔開來,就可以啦!
egrep -n 'g(la|oo)d' regular_express.txt
()+意義:多個重複群組的判別
範例:將『AxyzxyzxyzxyzC』用 echo 叫出,然後再使用如下的方法搜尋一下!
echo 'AxyzxyzxyzxyzC' | egrep 'A(xyz)+C'
上面的例子意思是說,我要找開頭是 A 結尾是 C ,中間有一個以上的 "xyz" 字串的意思~

以上這些就是延伸型的正規表示法的特殊字元。另外,要特別強調的是,那個 ! 在正規表示法當中並不是特殊字元,所以,如果你想要查出來檔案中含有 ! 與 > 的字行時,可以這樣:

These are the special characters of the extended regular expression. Also xff0c; special emphasis is xff0c; that! xff0c; xff0c; xff0c; xff0c; if you want to find files containing! and > lines xff0c; this can be done xff1a;

grep -n '[!>]' regular_express.txt

這樣可以瞭解了嗎?常常看到有陷阱的題目寫:『反向選擇這樣對否? '[!a-z]'?』,呵呵!是錯的呦~要 '[^a-z] 才是對的!至於更多關於正規表示法的進階文章,請參考文末的參考資料(註2)

xff1f; often xff1a; xff1a; xff1f; 39; [(a-z]' xff1f; ff0c; fff01; wrong xff5e; 39; xff01; a-z; ff01; ff01; and ffl2; and xff0c) more advanced articles on positive expression; see references at the end of the document ()

 
大標題的圖示文件的格式化與相關處理

接下來讓我們來將文件進行一些簡單的編排吧!底下這些動作可以將你的訊息進行排版的動作,不需要重新以 vim 去編輯,透過資料流重導向配合底下介紹的 printf 功能,以及 awk 指令,就可以讓你的訊息以你想要的模樣來輸出了!試看看吧!

Let's move on to a few simple layouts of the document & #xff01; below these actions can type your messages for & #xff0c; there is no need to re-edit & #xff0c with vim; redirecting through the data stream to match the prontf function & #xff0c; and awl command & #xff0c; allowing your messages to be delivered in the way you want ff01;



小標題的圖示 格式化列印: printf

在很多時候,我們可能需要將自己的資料給他格式化輸出的!舉例來說,考試卷分數的輸出,姓名與科目及分數之間,總是可以稍微作個比較漂亮的版面配置吧?例如我想要輸出底下的樣式:

In many cases xff0c; we may need to format his own data xff01; xff0c, for example; xff0c, output of test scores xff0c; xff0c, between name and subject and score; can always make a slightly better layout xff1f; for example, I want to output the following pattern xff1a;

Name     Chinese   English   Math    Average
DmTsai        80        60     92      77.33
VBird         75        55     80      70.00
Ken           60        90     70      73.33

上表的資料主要分成五個欄位,各個欄位之間可使用 tab 或空白鍵進行分隔。請將上表的資料轉存成為 printf.txt 檔名,等一下我們會利用這個檔案來進行幾個小練習的。因為每個欄位的原始資料長度其實並非是如此固定的 (Chinese 長度就是比 Name 要多),而我就是想要如此表示出這些資料,此時,就得需要列印格式管理員 printf 的幫忙了!printf 可以幫我們將資料輸出的結果格式化,而且而支援一些特殊的字符~底下我們就來看看!

The data in the above table is divided into five columns & #xff0c; the data in each field can be separated using tab or blank keys. Please transfer the data in the above table to the printf.txt file name & #xff0c; we will use this file for a few exercises later. Because the original data length in each field is not really that fixed (Chinese has more than a name) #xff0c; that's what I want to show the data #xff0c; at this point #xff0c; needing the help of print format manager #xff01; printf can help us format the results of the data output #xff0c; and support some special characters #xff5e; below we will look at #xff01;

[root@www ~]# printf '列印格式' 實際內容
選項與參數:
關於格式方面的幾個特殊樣式:
       \a    警告聲音輸出
       \b    倒退鍵(backspace)
       \f    清除螢幕 (form feed)
       
    輸出新的一行
       \r    亦即 Enter 按鍵
       	    水平的 [tab] 按鍵
       \v    垂直的 [tab] 按鍵
       \xNN  NN 為兩位數的數字,可以轉換數字成為字元。
關於 C 程式語言內,常見的變數格式
       %ns   那個 n 是數字, s 代表 string ,亦即多少個字元;
       %ni   那個 n 是數字, i 代表 integer ,亦即多少整數位數;
       %N.nf 那個 n 與 N 都是數字, f 代表 floating (浮點),如果有小數位數,
             假設我共要十個位數,但小數點有兩位,即為 %10.2f 囉!

接下來我們來進行幾個常見的練習。假設所有的資料都是一般文字 (這也是最常見的狀態),因此最常用來分隔資料的符號就是 [Tab] 啦!因為 [Tab] 按鍵可以將資料作個整齊的排列!那麼如何利用 printf 呢?參考底下這個範例:

Let us proceed with some of the usual exercises. Let's assume that all the data are general text (which is also the most common state) & #xff0c; so the most commonly used symbol to separate the data is [Tab] la & #xff01; because the [Tab] key allows the data to be arranged in a coherent manner & #xff01; then how to use the printf & #xff1f; refer to this example below & #xff1a;

範例一:將剛剛上頭資料的檔案 (printf.txt) 內容僅列出姓名與成績:(用 [tab] 分隔)
[root@www ~]# printf '%s	 %s	 %s	 %s	 %s	 
' $(cat printf.txt)
Name     Chinese         English         Math    Average
DmTsai   80      60      92      77.33
VBird    75      55      80      70.00
Ken      60      90      70      73.33

由於 printf 並不是管線命令,因此我們得要透過類似上面的功能,將檔案內容先提出來給 printf 作為後續的資料才行。如上所示,我們將每個資料都以 [tab] 作為分隔,但是由於 Chinese 長度太長,導致 English 中間多了一個 [tab] 來將資料排列整齊!啊~結果就看到資料對齊結果的差異了!

Since pruntf is not a pipe command & #xff0c; therefore, we have to put the file content through a similar function & #xff0c; to present it to pruntf as a subsequent data. As shown above & #xff0c; we have [tab] as a partition & #xff0c; but because China is too long #xff0c; leading to an [tab] in English to align the data #xff01; #xff5e; and we see differences in data matching results #xff01;

另外,在 printf 後續的那一段格式中,%s 代表一個不固定長度的字串,而字串與字串中間就以 這個 [tab]分隔符號來處理!你要記得的是,由於 與 %s 中間還有空格,因此每個字串間會有一個 [tab] 與一個空白鍵的分隔喔!

Also xff0c; xff0c; %s for an unfixed length string xff0c; and xff01 for the string and the string with the [tab] separator; you remember xff0c; because there are spaces xff0c in the middle of %s; so each string has a [tab] and a blank key separated xff01;

既然每個欄位的長度不固定會造成上述的困擾,那我將每個欄位固定就好啦!沒錯沒錯!這樣想非常好!所以我們就將資料給他進行固定欄位長度的設計吧!

Since the length of each column is irregular, it causes the above-mentioned disturbance #xff0c; I'll fix each column #xff01; yes #xff01; that's very good #xff01; so let's give him a fixed column length design #xff01;

範例二:將上述資料關於第二行以後,分別以字串、整數、小數點來顯示:
[root@www ~]# printf '%10s %5i %5i %5i %8.2f 
' $(cat printf.txt |\
> grep -v Name)
    DmTsai    80    60    92    77.33
     VBird    75    55    80    70.00
       Ken    60    90    70    73.33

上面這一串格式想必您看得很辛苦!沒關係!一個一個來解釋!上面的格式共分為五個欄位, %10s 代表的是一個長度為 10 個字元的字串欄位,%5i 代表的是長度為 5 個字元的數字欄位,至於那個 %8.2f 則代表長度為 8 個字元的具有小數點的欄位,其中小數點有兩個字元寬度。我們可以使用底下的說明來介紹 %8.2f 的意義:

The above series of formats must have been very hard for you to see xff01; xff01; xff01; one to explain xff01; the above format is divided into five columns xff0c; %10s is a string field with a length of 10 characters xff0c; %5i is a numeric field with a length of 5 characters xff0c; and that %8.2f is a smaller field with a length of 8 characters xff0c; there are two dimensions of the decimal points. We can use the description below to describe the meaning of %8.2f #xff1a;

字元寬度: 12345678
%8.2f意義:00000.00

如上所述,全部的寬度僅有 8 個字元,整數部分佔有 5 個字元,小數點本身 (.) 佔一位,小數點下的位數則有兩位。這種格式經常使用於數值程式的設計中!這樣瞭解乎?自己試看看如果要將小數點位數變成 1 位又該如何處理?

As noted above & #xff0c; the full width is only 8 characters & #xff0c; the integer part is 5 characters & #xff0c; the decimal point itself (...) is one & #xff0c; the decimal number is two places. This format is often used in the design of the numeric program & #xff01; this is understood by #xff1f; see for itself how to handle #xff1f if the decimal is to become 1 bit;

printf 除了可以格式化處理之外,他還可以依據 ASCII 的數字與圖形對應來顯示資料喔(註3)!舉例來說 16 進位的 45 可以得到什麼 ASCII 的顯示圖 (其實是字元啦)?

In addition to formatting, , he can also display data based on ASCII numbers and graphs (

範例三:列出 16 進位數值 45 代表的字元為何?
[root@www ~]# printf '\x45
'
E
# 這東西也很好玩~他可以將數值轉換成為字元,如果你會寫 script 的話,
# 可以自行測試一下,由 20~80 之間的數值代表的字元是啥喔! ^_^

printf 的使用相當的廣泛喔!包括等一下後面會提到的 awk 以及在 C 程式語言當中使用的螢幕輸出,都是利用 printf 呢!鳥哥這裡也只是列出一些可能會用到的格式而已,有興趣的話,可以自行多作一些測試與練習喔! ^_^

Printf uses fairly wide-ranging & #xff01; includes awk and screen output & #xff0c, which will be mentioned later in the language of the C program; all use printf & #xff01; Bird here is just a list of possible formats & #xff0c; #xff0c if interested; can do some extra tests and exercises on its own #xff01;

Tips:
列印格式化這個 printf 指令,乍看之下好像也沒有什麼很重要的~不過,如果你需要自行撰寫一些軟體,需要將一些資料在螢幕上頭漂漂亮亮的輸出的話,那麼 printf 可也是一個很棒的工具喔!
鳥哥的圖示

小標題的圖示 awk:好用的資料處理工具

awk 也是一個非常棒的資料處理工具!相較於 sed 常常作用於一整個行的處理, awk 則比較傾向於一行當中分成數個『欄位』來處理。因此,awk 相當的適合處理小型的數據資料處理呢!awk通常運作的模式是這樣的:

Awak is also a very good data processing tool & #xff01; instead of sed, which often works in a line & #xff0c; awl more towards a line with several `fields' to handle. & #xff0c; awk is an appropriate data processing tool for small amounts of data & #xff01; awk usually operates in the same way as #xff1a;

[root@www ~]# awk '條件類型1{動作1} 條件類型2{動作2} ...' filename

awk 後面接兩個單引號並加上大括號 {} 來設定想要對資料進行的處理動作。awk 可以處理後續接的檔案,也可以讀取來自前個指令的 standard output 。但如前面說的, awk 主要是處理『每一行的欄位內的資料』,而預設的『欄位的分隔符號為"空白鍵" 或 "[tab]鍵" 』!舉例來說,我們用 last 可以將登入者的資料取出來,結果如下所示:

Awl followed by two single quotes and a big number {} to set the action to be taken with regard to the data. Awl can process the following file & #xff0c; or can read the standard output from the previous command. But as , awk mainly handles "data in each line" xff0c; the default column separators are 34; blank keys #34; or & #34; [tab]key #34; #xff01; for example xff0c; we can use the last to remove the entry data xff0c; and xff1a, as shown below;

[root@www ~]# last -n 5 <==僅取出前五行
root     pts/1   192.168.1.100  Tue Feb 10 11:21   still logged in
root     pts/1   192.168.1.100  Tue Feb 10 00:46 - 02:28  (01:41)
root     pts/1   192.168.1.100  Mon Feb  9 11:41 - 18:30  (06:48)
dmtsai   pts/1   192.168.1.100  Mon Feb  9 11:41 - 11:41  (00:00)
root     tty1                   Fri Sep  5 14:09 - 14:10  (00:01)

若我想要取出帳號與登入者的 IP ,且帳號與 IP 之間以 [tab] 隔開,則會變成這樣:

If I want to remove the account from the login IP & #xff0c; and separate the account from the login & #xff0c by [tab]; this becomes #xff1a;

[root@www ~]# last -n 5 | awk '{print $1 "	" $3}'
root    192.168.1.100
root    192.168.1.100
root    192.168.1.100
dmtsai  192.168.1.100
root    Fri

上表是 awk 最常使用的動作!透過 print 的功能將欄位資料列出來!欄位的分隔則以空白鍵或 [tab] 按鍵來隔開。因為不論哪一行我都要處理,因此,就不需要有 "條件類型" 的限制!我所想要的是第一欄以及第三欄,但是,第五行的內容怪怪的~這是因為資料格式的問題啊!所以囉~使用 awk的時候,請先確認一下你的資料當中,如果是連續性的資料,請不要有空格或 [tab] 在內,否則,就會像這個例子這樣,會發生誤判喔!

The table above is the most commonly used action by awk & #xff01; lists column data in & #xff01 through prent functions; divides columns by blank or [tab] keys. Because I have to deal with & #xff0c; & & #xff0c; therefore & 34; Conditional #34; Limitation & #xff01; I want column 1 and column 3 xff0c; xff0c; xff5e in line 5; this is because of data format problems & #xff01; so xff5e; xk xff0c; check that your data #xff0c; if it is consecutive #xff0c; please do not have any space or [tab] #xff0c; or #x0x0x0xx; this & ffxxxx

另外,由上面這個例子你也會知道,在每一行的每個欄位都是有變數名稱的,那就是 $1, $2... 等變數名稱。以上面的例子來說, root 是 $1 ,因為他是第一欄嘛!至於 192.168.1.100 是第三欄,所以他就是 $3 啦!後面以此類推~呵呵!還有個變數喔!那就是 $0 ,$0 代表『一整列資料』的意思~以上面的例子來說,第一行的 $0 代表的就是『root .... 』那一行啊!由此可知,剛剛上面五行當中,整個 awk 的處理流程是:

Also xff0c; by this example, you will also know that xff0c; each column in

  1. 讀入第一行,並將第一行的資料填入 $0, $1, $2.... 等變數當中;
  2. 依據 "條件類型" 的限制,判斷是否需要進行後面的 "動作";
  3. 做完所有的動作與條件類型;
  4. 若還有後續的『行』的資料,則重複上面 1~3 的步驟,直到所有的資料都讀完為止。

經過這樣的步驟,你會曉得, awk 是『以行為一次處理的單位』,而『以欄位為最小的處理單位』。好了,那麼 awk 怎麼知道我到底這個資料有幾行?有幾欄呢?這就需要 awk 的內建變數的幫忙啦~

After such a step #xff0c; you'll know xff0c; awk is the unit of & #xff0c with the word ; and 變數名稱代表意義NF每一行 ($0) 擁有的欄位總數NR目前 awk 所處理的是『第幾行』資料FS目前的分隔字元,預設是空白鍵

我們繼續以上面 last -n 5 的例子來做說明,如果我想要:

Let's continue with the last-n-5 example of #xff0c; if I want #xff1a;

  • 列出每一行的帳號(就是 $1);
  • 列出目前處理的行數(就是 awk 內的 NR 變數)
  • 並且說明,該行有多少欄位(就是 awk 內的 NF 變數)

則可以這樣:

#xff1a.

Tips:
要注意喔,awk 後續的所有動作是以單引號『 ' 』括住的,由於單引號與雙引號都必須是成對的,所以, awk 的格式內容如果想要以 print 列印時,記得非變數的文字部分,包含上一小節 printf 提到的格式中,都需要使用雙引號來定義出來喔!因為單引號已經是 awk 的指令固定用法了!
鳥哥的圖示
[root@www ~]# last -n 5| awk '{print $1 "	 lines: " NR "	 columns: " NF}'
root     lines: 1        columns: 10
root     lines: 2        columns: 10
root     lines: 3        columns: 10
dmtsai   lines: 4        columns: 10
root     lines: 5        columns: 9
# 注意喔,在 awk 內的 NR, NF 等變數要用大寫,且不需要有錢字號 $ 啦!

這樣可以瞭解 NR 與 NF 的差別了吧?好了,底下來談一談所謂的 "條件類型" 了吧!

So you can see the difference between NR and NF #xff1f; good & #xff0c; below we talk about what we call & #34; condition type #34; right #xff01;



  • awk 的邏輯運算字元

既然有需要用到 "條件" 的類別,自然就需要一些邏輯運算囉~例如底下這些:

If there is a need to use & #34; Condition & #34; Class & #xff0c; Naturally, some logic is required & #xff5e; for example, these & #xff1a below;

運算單元代表意義
>大於
<小於
>=大於或等於
<=小於或等於
==等於
!=不等於

值得注意的是那個『 == 』的符號,因為:

Noteworthy is the symbol xff0c #61; #61; ; because xff1a;

  • 邏輯運算上面亦即所謂的大於、小於、等於等判斷式上面,習慣上是以『 == 』來表示;
  • 如果是直接給予一個值,例如變數設定時,就直接使用 = 而已。

好了,我們實際來運用一下邏輯判斷吧!舉例來說,在 /etc/passwd 當中是以冒號 ":" 來作為欄位的分隔,該檔案中第一欄位為帳號,第三欄位則是 UID。那假設我要查閱,第三欄小於 10 以下的數據,並且僅列出帳號與第三欄,那麼可以這樣做:

All right, #xff0c; let's actually run the logic ! #xff0c; for example /etc/passwd in colon & #34; " " for segregation of columns & #xff0c; the first column in the file is account #xff0c; the third column is UID. That assumes I'm going to look at xff0c; the third column is less than 10 & #xff0c; and only the account number and the third column #xff0c; then #xff1a;

[root@www ~]# cat /etc/passwd | \
> awk '{FS=":"} $3 < 10 {print $1 "	 " $3}'
root:x:0:0:root:/root:/bin/bash
bin      1
daemon   2
....(以下省略)....

有趣吧!不過,怎麼第一行沒有正確的顯示出來呢?這是因為我們讀入第一行的時候,那些變數 $1, $2... 預設還是以空白鍵為分隔的,所以雖然我們定義了 FS=":" 了,但是卻僅能在第二行後才開始生效。那麼怎麼辦呢?我們可以預先設定 awk 的變數啊!利用 BEGIN 這個關鍵字喔!這樣做:

Interestingly xff01; but xff0c; how is the first line not shown correctly xff1f; this is because when we read the first line xff0c; those variables $1,$2... defaulted or space-separated xff0c; so although we have defined FS#61; 34; 34; xff0c; but only became effective after the second line xff1f; we can preset the awk variable xff01; use the BEGIN key ff01; do this xff1a;

[root@www ~]# cat /etc/passwd | \
> awk 'BEGIN {FS=":"} $3 < 10 {print $1 "	 " $3}'
root     0
bin      1
daemon   2
......(以下省略)......

很有趣吧!而除了 BEGIN 之外,我們還有 END 呢!另外,如果要用 awk 來進行『計算功能』呢?以底下的例子來看,假設我有一個薪資資料表檔名為 pay.txt ,內容是這樣的:

Interesting xff01; plus BEGIN xff0c; we have END xff01; xff0c; xff1f; xff0c for example below; assuming that I have a pay.txt & #xff0c; this is xff1a;

Name    1st     2nd     3th
VBird   23000   24000   25000
DMTsai  21000   20000   23000
Bird2   43000   42000   41000

如何幫我計算每個人的總額呢?而且我還想要格式化輸出喔!我們可以這樣考慮:

How to help me calculate the sum of everyone #xff1f; and I want to format output #xff01; this is how we can think about #xff1a;

  • 第一行只是說明,所以第一行不要進行加總 (NR==1 時處理);
  • 第二行以後就會有加總的情況出現 (NR>=2 以後處理)
[root@www ~]# cat pay.txt | \
> awk 'NR==1{printf "%10s %10s %10s %10s %10s
",$1,$2,$3,$4,"Total" }
NR>=2{total = $2 + $3 + $4
printf "%10s %10d %10d %10d %10.2f
", $1, $2, $3, $4, total}'
      Name        1st        2nd        3th      Total
     VBird      23000      24000      25000   72000.00
    DMTsai      21000      20000      23000   64000.00
     Bird2      43000      42000      41000  126000.00

上面的例子有幾個重要事項應該要先說明的:

There are a few important things that should be mentioned above: #xff1a; #xff1a.

  • awk 的指令間隔:所有 awk 的動作,亦即在 {} 內的動作,如果有需要多個指令輔助時,可利用分號『;』間隔,或者直接以 [Enter] 按鍵來隔開每個指令,例如上面的範例中,鳥哥共按了三次 [enter] 喔!
  • 邏輯運算當中,如果是『等於』的情況,則務必使用兩個等號『==』!
  • 格式化輸出時,在 printf 的格式設定當中,務必加上 ,才能進行分行!
  • 與 bash shell 的變數不同,在 awk 當中,變數可以直接使用,不需加上 $ 符號。

利用 awk 這個玩意兒,就可以幫我們處理很多日常工作了呢!真是好用的很~此外, awk 的輸出格式當中,常常會以 printf 來輔助,所以,最好你對 printf 也稍微熟悉一下比較好啦!另外, awk 的動作內 {} 也是支援 if (條件) 的喔!舉例來說,上面的指令可以修訂成為這樣:

xff0c; often xff0c; so xff0c; best to get a little familiar with printf xff01; also xff0x1 ; xff

[root@www ~]# cat pay.txt | \
> awk '{if(NR==1) printf "%10s %10s %10s %10s %10s
",$1,$2,$3,$4,"Total"}
NR>=2{total = $2 + $3 + $4
printf "%10s %10d %10d %10d %10.2f
", $1, $2, $3, $4, total}'

你可以仔細的比對一下上面兩個輸入有啥不同~從中去瞭解兩種語法吧!我個人是比較傾向於使用第一種語法,因為會比較有統一性啊! ^_^

You can carefully compare the two above xff5e; get to know the two syntaxes xff01; I personally prefer to use the first syntax xff0c; because it is more homogenous xff01;

除此之外, awk 還可以幫我們進行迴圈計算喔!真是相當的好用!不過,那屬於比較進階的單獨課程了,我們這裡就不再多加介紹。如果你有興趣的話,請務必參考延伸閱讀中的相關連結喔 (註4)。

In addition to this, #xff0c; awlf01; #xff01; it's a very good use & #xff01; & #xff0c; it's a more advanced solo class & #xff0c; we don't introduce more. If you're interested & #xff0c; please refer to the links in the extended reading (4).


小標題的圖示 檔案比對工具

什麼時候會用到檔案的比對啊?通常是『同一個套裝軟體的不同版本之間,比較設定檔與原始檔的差異』。很多時候所謂的檔案比對,通常是用在 ASCII 純文字檔的比對上的!那麼比對檔案的指令有哪些?最常見的就是 diff 囉!另外,除了 diff 比對之外,我們還可以藉由 cmp 來比對非純文字檔!同時,也能夠藉由 diff 建立的分析檔,以處理補丁 (patch) 功能的檔案呢!就來玩玩先!

xff1f; usually between different versions of the same set of software xff0c; comparing profiles to original files xff0c; often xff0c; usually xff01 on ASCII plain text files; xfffff on file instructions; most commonly diffrey xff01; xff0c; other than diff compared to diff xff0c; we can play by cmp compared to non-pure text files xff01; same time xffff0c; and can also use diff to create analytical files xff0c; to process functional files ff01;


  • diff

diff 就是用在比對兩個檔案之間的差異的,並且是以行為單位來比對的!一般是用在 ASCII 純文字檔的比對上。由於是以行為比對的單位,因此 diff 通常是用在同一的檔案(或軟體)的新舊版本差異上!舉例來說,假如我們要將 /etc/passwd 處理成為一個新的版本,處理方式為:將第四行刪除,第六行則取代成為『no six line』,新的檔案放置到 /tmp/test 裡面,那麼應該怎麼做?

diff is xff01, which is used to compare differences between two files; and xff01, which is used as a unit of conduct; which is usually used to compare square text files in ASCII. Since xff0c, which is used as a unit of behaviour, ; xff0c if we want to treat /etc/passwd as a new version xff0c; xff1a; delete xff0c in the fourth line; xff0c for the sixth line; xff0c for the new file; tmp/test xff0c; what should we do?

[root@www ~]# mkdir -p /tmp/test <==先建立測試用的目錄
[root@www ~]# cd /tmp/test
[root@www test]# cp /etc/passwd passwd.old
[root@www test]# cat /etc/passwd | \
> sed -e '4d' -e '6c no six line' > passwd.new
# 注意一下, sed 後面如果要接超過兩個以上的動作時,每個動作前面得加 -e 才行!
# 透過這個動作,在 /tmp/test  裡面便有新舊的 passwd 檔案存在了!

接下來討論一下關於 diff 的用法吧!

Let's discuss the use of diff #xff01;

[root@www ~]# diff [-bBi] from-file to-file
選項與參數:
from-file :一個檔名,作為原始比對檔案的檔名;
to-file   :一個檔名,作為目的比對檔案的檔名;
注意,from-file 或 to-file 可以 - 取代,那個 - 代表『Standard input』之意。

-b  :忽略一行當中,僅有多個空白的差異(例如 "about me" 與 "about     me" 視為相同
-B  :忽略空白行的差異。
-i  :忽略大小寫的不同。

範例一:比對 passwd.old 與 passwd.new 的差異:
[root@www test]# diff passwd.old passwd.new
4d3    <==左邊第四行被刪除 (d) 掉了,基準是右邊的第三行
< adm:x:3:4:adm:/var/adm:/sbin/nologin  <==這邊列出左邊(<)檔案被刪除的那一行內容
6c5    <==左邊檔案的第六行被取代 (c) 成右邊檔案的第五行
< sync:x:5:0:sync:/sbin:/bin/sync  <==左邊(<)檔案第六行內容
---
> no six line                      <==右邊(>)檔案第五行內容
# 很聰明吧!用 diff 就把我們剛剛的處理給比對完畢了!

用 diff 比對檔案真的是很簡單喔!不過,你不要用 diff 去比對兩個完全不相干的檔案,因為比不出個啥咚咚!另外, diff 也可以比對整個目錄下的差異喔!舉例來說,我們想要瞭解一下不同的開機執行等級 (runlevel) 內容有啥不同?假設你已經知道執行等級 3 與 5 的啟動腳本分別放置到 /etc/rc3.d 及 /etc/rc5.d ,則我們可以將兩個目錄比對一下:

It's really easy to compare diff to files & xff01; xff0c; xff0c; xiff0c; xiff0c; xiff0c; diff xff01; xff0c; xff0c for example; we want to know what different levels of start-up (runlevel) are; xff1f; assuming you already know that the start-up scripts of 3 and 5 are placed separately to /etc/rc3.d and /etc/rc5.d & #xff0c; then we can compare the two directories to xff1a;

[root@www ~]# diff /etc/rc3.d/ /etc/rc5.d/
Only in /etc/rc3.d/: K99readahead_later
Only in /etc/rc5.d/: S96readahead_later

我們的 diff 很聰明吧!還可以比對不同目錄下的相同檔名的內容,這樣真的很方便喔~

Our diff is smart #xff01; it can be compared to the same file name in different directories #xff0c; it's really convenient xff5e;



  • cmp

相對於 diff 的廣泛用途, cmp 似乎就用的沒有這麼多了~ cmp 主要也是在比對兩個檔案,他主要利用『位元組』單位去比對,因此,當然也可以比對 binary file 囉~(還是要再提醒喔, diff 主要是以『行』為單位比對,cmp 則是以『位元組』為單位去比對,這並不相同!)

& #xff0c; cmp seems to be short of ~ cmp is also mainly comparing two files & #xff0c; he mainly uses the byte unit to #xff0c; & #xff0c; thus, of course, it can also be compared to binary file #xff5e; again, #xff0c; diff is mainly by `line' & #xff0c; cmp is by #xff0c; this is not the same #xff01;)

[root@www ~]# cmp [-l] file1 file2
選項與參數:
-l  :將所有的不同點的位元組處都列出來。因為 cmp 預設僅會輸出第一個發現的不同點。

範例一:用 cmp 比較一下 passwd.old 及 passwd.new
[root@www test]# cmp passwd.old passwd.new
passwd.old passwd.new differ: byte 106, line 4

看到了嗎?第一個發現的不同點在第四行,而且位元組數是在第 106 個位元組處!這個 cmp 也可以用來比對 binary 啦! ^_^

See #xff1f; first found difference in line 4xff0c; and bytes in the 106th byte & #xff01; this cmp can also be compared to binary & #xff01; br/>


  • patch

patch 這個指令與 diff 可是有密不可分的關係啊!我們前面提到,diff 可以用來分辨兩個版本之間的差異,舉例來說,剛剛我們所建立的 passwd.old 及 passwd.new 之間就是兩個不同版本的檔案。那麼,如果要『升級』呢?就是『將舊的檔案升級成為新的檔案』時,應該要怎麼做呢?其實也不難啦!就是『先比較先舊版本的差異,並將差異檔製作成為補丁檔,再由補丁檔更新舊檔案』即可。舉例來說,我們可以這樣做測試:

This directive has an indistinguishable relationship with diff. & #xff01; we mentioned earlier & #xff0c; diff can be used to distinguish differences between the two versions & #xff0c; & #xff0c; just created & passwd.old and passwd.new are two different versions of the file. & #xff0c; if xff1f; if to upgrade the old file to a new file & xff0c ; what should we do #xff1f; it's not difficult #xff01; it's the difference of the older version xff0c; it's possible to update the old file #x0c; it's possible to test #fffx1 ; it's the difference of the previous version #xff0c; it's #xffffff0c ; it is possible to update the old file.

範例一:以 /tmp/test 內的 passwd.old 與 passwd.new  製作補丁檔案
[root@www test]# diff -Naur passwd.old passwd.new > passwd.patch
[root@www test]# cat passwd.patch
--- passwd.old  2009-02-10 14:29:09.000000000 +0800 <==新舊檔案的資訊
+++ passwd.new  2009-02-10 14:29:18.000000000 +0800
@@ -1,9 +1,8 @@   <==新舊檔案要修改資料的界定範圍,舊檔在 1-9 行,新檔在 1-8 行
 root:x:0:0:root:/root:/bin/bash
 bin:x:1:1:bin:/bin:/sbin/nologin
 daemon:x:2:2:daemon:/sbin:/sbin/nologin
-adm:x:3:4:adm:/var/adm:/sbin/nologin      <==左側檔案刪除
 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
-sync:x:5:0:sync:/sbin:/bin/sync           <==左側檔案刪除
+no six line                               <==右側新檔加入
 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
 halt:x:7:0:halt:/sbin:/sbin/halt
 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin

一般來說,使用 diff 製作出來的比較檔案通常使用副檔名為 .patch 囉。至於內容就如同上面介紹的樣子。基本上就是以行為單位,看看哪邊有一樣與不一樣的,找到一樣的地方,然後將不一樣的地方取代掉!以上面表格為例,新檔案看到 - 會刪除,看到 + 會加入!好了,那麼如何將舊的檔案更新成為新的內容呢?就是將 passwd.old 改成與 passwd.new 相同!可以這樣做:

In general, xff0c; contrasted files made with diff are usually made with a synonym.patch. As for content, as described above. Basically, it's a behavioral unit xff0c; see where there's the same and different xff0c; find the same place xff0c; then replace xff01; use the table above as an example xff0c; see new files - delete xff0c; see #43; add xff01; xff0c; then how old files can be updated into new content xff1f; replace passwd.old with passwd.nff01; this can be done xff1a;

[root@www ~]# patch -pN < patch_file    <==更新
[root@www ~]# patch -R -pN < patch_file <==還原
選項與參數:
-p  :後面可以接『取消幾層目錄』的意思。
-R  :代表還原,將新的檔案還原成原來舊的版本。

範例二:將剛剛製作出來的 patch file 用來更新舊版資料
[root@www test]# patch -p0 < passwd.patch
patching file passwd.old
[root@www test]# ll passwd*
-rw-r--r-- 1 root root 1929 Feb 10 14:29 passwd.new
-rw-r--r-- 1 root root 1929 Feb 10 15:12 passwd.old <==檔案一模一樣!

範例三:恢復舊檔案的內容
[root@www test]# patch -R -p0 < passwd.patch
[root@www test]# ll passwd*
-rw-r--r-- 1 root root 1929 Feb 10 14:29 passwd.new
-rw-r--r-- 1 root root 1986 Feb 10 15:18 passwd.old
# 檔案就這樣恢復成為舊版本囉

為什麼這裡會使用 -p0 呢?因為我們在比對新舊版的資料時是在同一個目錄下,因此不需要減去目錄啦!如果是使用整體目錄比對 (diff 舊目錄 新目錄) 時,就得要依據建立 patch 檔案所在目錄來進行目錄的刪減囉!

Why do you use -p0 here? xff1f; because we're using xff0c in the same directory when comparing data with older ones; therefore, there is no need to delete the directory xff01; xff0c when using the whole directory matching (diff old directory, new directory) xff01; there is a need to delete the directory based on the folder where the patch files are created xff01;

更詳細的 patch 用法我們會在後續的第五篇的原始碼編譯 (第二十二章)再跟大家介紹,這裡僅是介紹給你,我們可以利用 diff 來比對兩個檔案之間的差異,更可進一步利用這個功能來製作修補檔案 (patch file) ,讓大家更容易進行比對與升級呢!很不賴吧! ^_^

A more detailed patch will be used to introduce to you xff0c to introduce xff0c; this is only for you xff0c; we can use diff to compare differences between the two files xff0c; we can use this function to make a better repair of files (patchfile) & xff0c; make it easier to compare to upgrades ff01; it's easy to compare xff01; fff01


小標題的圖示 檔案列印準備: pr

如果你曾經使用過一些圖形介面的文書處理軟體的話,那麼很容易發現,當我們在列印的時候,可以同時選擇與設定每一頁列印時的標頭吧!也可以設定頁碼呢!那麼,如果我是在 Linux 底下列印純文字檔呢可不可以具有標題啊?可不可以加入頁碼啊?呵呵!當然可以啊!使用 pr 就能夠達到這個功能了。不過, pr 的參數實在太多了,鳥哥也說不完,一般來說,鳥哥都僅使用最簡單的方式來處理而已。舉例來說,如果想要列印 /etc/man.config 呢?

xff0c; xff0c; xff0c; xff0c when we're printing; xff0c; xyff01; xff01; xff01; xff01; ff0c; xff0c; xff0c; xffff; xff1f; xfff; xfff; xff01; xff01; r; this function can be achieved. But xff0c; pr refers to too many xff0c; xfffffxf; ffffff; ; xfff); xfff; and p.p.

[root@www ~]# pr /etc/man.config


2007-01-06 18:24                 /etc/man.config                  Page 1


#
# Generated automatically from man.conf.in by the
# configure script.
.....以下省略......

上面特殊字體那一行呢,其實就是使用 pr 處理後所造成的標題啦!標題中會有『檔案時間』、『檔案檔名』及『頁碼』三大項目。更多的 pr 使用,請參考 pr 的說明啊! ^_^

The line with the special fonts above xff0c; it's actually the title xff01 created by using the pr process; there's three headings: File Time, File Name, and Page Code. More prs use xff0c; see pr's instructions xff01;


大標題的圖示重點回顧
  • 正規表示法就是處理字串的方法,他是以行為單位來進行字串的處理行為;
  • 正規表示法透過一些特殊符號的輔助,可以讓使用者輕易的達到『搜尋/刪除/取代』某特定字串的處理程序;
  • 只要工具程式支援正規表示法,那麼該工具程式就可以用來作為正規表示法的字串處理之用;
  • 正規表示法與萬用字元是完全不一樣的東西!萬用字元 (wildcard) 代表的是 bash 操作介面的一個功能,但正規表示法則是一種字串處理的表示方式!
  • 使用 grep 或其他工具進行正規表示法的字串比對時,因為編碼的問題會有不同的狀態,因此, 你最好將 LANG 等變數設定為 C 或者是 en 等英文語系!
  • grep 與 egrep 在正規表示法裡面是很常見的兩支程式,其中, egrep 支援更嚴謹的正規表示法的語法;
  • 由於編碼系統的不同,不同的語系 (LANG) 會造成正規表示法擷取資料的差異。因此可利用特殊符號如 [:upper:] 來替代編碼範圍較佳;
  • 由於嚴謹度的不同,正規表示法之上還有更嚴謹的延伸正規表示法;
  • 基礎正規表示法的特殊字符有: *, ., [], [-], [^], ^, $ 等!
  • 常見的正規表示法工具有: grep , sed, vim 等等
  • printf 可以透過一些特殊符號來將資料進行格式化輸出;
  • awk 可以使用『欄位』為依據,進行資料的重新整理與輸出;
  • 文件的比對中,可利用 diff 及 cmp 進行比對,其中 diff 主要用在純文字檔案方面的新舊版本比對
  • patch 指令可以將舊版資料更新到新版 (主要亦由 diff 建立 patch 的補丁來源檔案)

大標題的圖示本章習題
( 要看答案請將滑鼠移動到『答:』底下的空白處,按下左鍵圈選空白處即可察看 )
  • 情境模擬題一:透過 grep 搜尋特殊字串,並配合資料流重導向來處理大量的檔案搜尋問題。

    • 目標:正確的使用正規表示法;
    • 前提:需要瞭解資料流重導向,以及透過子指令 $(command) 來處理檔名的搜尋;

    我們簡單的以搜尋星號 (*) 來處理底下的任務:

    1. 利用正規表示法找出系統中含有某些特殊關鍵字的檔案,舉例來說,找出在 /etc 底下含有星號 (*) 的檔案與內容:

      解決的方法必須要搭配萬用字元,但是星號本身就是正規表示法的字符,因此需要如此進行:
      [root@www ~]# grep '\*' /etc/*
      
      你必須要注意的是,在單引號內的星號是正規表示法的字符,但我們要找的是星號,因此需要加上跳脫字符 (\)。但是在 /etc/* 的那個 * 則是 bash 的萬用字元!代表的是檔案的檔名喔!不過由上述的這個結果中,我們僅能找到 /etc 底下第一層子目錄的資料,無法找到次目錄的資料,如果想要連同完整的 /etc 次目錄資料,就得要這樣做:
      [root@www ~]# grep '\*' $(find /etc -type f)
      

    2. 但如果檔案數量太多呢?如同上述的案例,如果要找的是全系統 (/) 呢?你可以這樣做:
      [root@www ~]# grep '\*' $(find / -type f)
      -bash: /bin/grep: Argument list too long
      
      真要命!由於指令列的內容長度是有限制的,因此當搜尋的對象是整個系統時,上述的指令會發生錯誤。那該如何是好?此時我們可以透過管線命令以及 xargs 來處理。舉例來說,讓 grep 每次僅能處理 10 個檔名,此時你可以這樣想:

      1. 先用 find 去找出檔案;
      2. 用 xargs 將這些檔案每次丟 10 個給 grep 來作為參數處理;
      3. grep 實際開始搜尋檔案內容。

      所以整個作法就會變成這樣:
      [root@www ~]# find / -type f | xargs -n 10 grep '\*'
      

    3. 從輸出的結果來看,資料量實在非常龐大!那如果我只是想要知道檔名而已呢?你可以透過 grep 的功能來找到如下的參數!
      [root@www ~]# find / -type f | xargs -n 10 grep -l '\*'
      

  • 情境模擬題二:使用管線命令配合正規表示法建立新指令與新變數。我想要建立一個新的指令名為 myip ,這個指令能夠將我系統的 IP 捉出來顯示。而我想要有個新變數,變數名為 MYIP ,這個變數可以記錄我的 IP 。

    處理的方式很簡單,我們可以這樣試看看:

    1. 首先,我們依據本章內的 ifconfig, sed 與 awk 來取得我們的 IP ,指令為:
      [root@www ~]# ifconfig eth0 | grep 'inet addr' | \
      >  sed 's/^.*inet addr://g'| cut -d ' ' -f1
      
    2. 再來,我們可以將此指令利用 alias 指定為 myip 喔!如下所示:
      [root@www ~]# alias myip="ifconfig eth0 | grep 'inet addr' | \
      >  sed 's/^.*inet addr://g'| cut -d ' ' -f1 "
      
    3. 最終,我們可以透過變數設定來處理 MYIP 喔!
      [root@www ~]# MYIP=$( myip )
      
    4. 如果每次登入都要生效,可以將 alias 與 MYIP 的設定那兩行,寫入你的 ~/.bashrc 即可!


簡答題部分:
  • 我想要知道,在 /etc 底下,只要含有 XYZ 三個字元的任何一個字元的那一行就列出來,要怎樣進行?
    grep [XYZ] /etc/*
  • 將 /etc/termcap 內容取出後,(1)去除開頭為 # 的行 (2)去除空白行 (3)取出開頭為英文字母的那幾行 (4)最終統計總行數該如何進行?
    grep -v '^#' /etc/termcap | grep -v '^$' | grep '^[[:alpha:]]' | wc -l

大標題的圖示參考資料與延伸閱讀

2002/07/29:第一次完成;
2003/02/10:重新編排與加入 FAQ ;
2005/01/28:重新彙整基礎正規表示法的內容!重點在 regular_express.txt 的處理與練習上!
2005/03/30:修訂了 grep -n 'goo*g' regular_express.txt 這一段
2005/05/23:修訂了 grep -n '^[a-z]' regular_express.txt 所要擷取的是小寫,之前寫成大寫,錯了!
2005/08/22:加入了 awk, sed 等工具的介紹,還有 diff 與 cmp 等指令的說明!
2005/09/05:加入 printf 內,關於 \xNN 的說明!
2006/03/10:將原本的 sed 內的動作(action)中, s 由『搜尋』改成『取代』了!
2006/10/05:在 sed 當中多了一個 -i 的參數說明,也多了一個範例八可以參考。感謝討論區的thyme兄!
2008/10/08:加入 grep 內的 --color=auto 說明!
2009/02/07:將舊的基於 FC4 版本的文章移動到此處
2009/02/10:重新排版,並且加入語系的說明,以及特殊 [:資料:] 的說明!更改不少範例的說明。
2009/05/14:感謝網友 Jack 的回報, cmp 應該是使用『位元組 bytes』而非位元 bits,感謝 Jack 兄。
2009/08/26:加入情境模擬題目了!
2010/04/16:由linux_task兄提供的意見,將原本的 * 說明訂正一些部分,可讀性較佳!感謝您!

2002/06/28 以來統計人數
計數器
????

文字格式和图片示例

注册有任何问题请添加 微信:MVIP619 拉你进入群

弹窗与图片大小一致 文章转载注明 网址:https://netpsp.com/?id=70418

美化布局示例

欧易(OKX)最新版本

【遇到注册下载问题请加文章最下面的客服微信】永久享受返佣20%手续费!

APP下载   全球官网 大陆官网

币安(Binance)最新版本

币安交易所app【遇到注册下载问题请加文章最下面的客服微信】永久享受返佣20%手续费!

APP下载   官网地址

火币HTX最新版本

火币老牌交易所【遇到注册下载问题请加文章最下面的客服微信】永久享受返佣20%手续费!

APP下载   官网地址
可以去百度分享获取分享代码输入这里。
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

发表评论
平台列表
美化布局示例

欧易(OKX)

  全球官网 大陆官网

币安(Binance)

  官网

火币(HTX)

  官网

Gate.io

  官网

Bitget

  官网

deepcoin

  官网
关注我们

若遇到问题,加微信客服---清歌

搜索
排行榜
扫一扫,加我为微信好友加我为微信好友