1. 程式人生 > >shell指令碼之正則表示式、函式、grep、sed、awk、printf等基本命令配置詳解

shell指令碼之正則表示式、函式、grep、sed、awk、printf等基本命令配置詳解

一、正則表示式

簡介:

正則表示式(或稱Regular Expression,簡稱RE)就是由普通字元(例如字元 a 到 z)以及特殊字元(稱為元字元)組成的文字模式。該模式描述在查詢文字主體時待匹配的一個或多個字串。正則表示式作為一個模板,將某個字元模式與所搜尋的字串進行匹配。簡單的說,正則表示式就是處理字串的方法,它是以行為單位來進行字串的處理行為,正則表示式通過一些特殊符號的輔助,可以讓使用者輕易的達到搜尋/刪除/取代某特定字串的處理程式。vim、grep、find、awk、sed等命令都支援正則表示式。

常用正則表示式:

1、.代表任意單個字元, 如:/l..e/與包含一個l,後跟兩個字元,然後跟一個e的行相匹配

2、^代表行的開始。 ^love 如:與所有love開頭的行匹配

3、$代表行的結束。love$ 如:與所有love結尾的行匹配

那麼‘^$’ 就表示空行

4、[…]匹配括號中的字元之一

[abc]      匹配單個字元a或b或c

[123]      匹配單個字元1或2或3

[a-z]      匹配小寫字母a-z之一

[a-zA-Z]    匹配任意英文字母之一

[0-9a-zA-Z]匹配任意英文字母或數字之一

注意:上面標紅色的單個和之一,不管[]裡面多複雜,它的結果都是一個字元!

可以用^標記做[]內的字首,表示[]內的字元之外的其他字元(即匹配不在此括號中的任何字元)。比如 搜尋oo前沒有g的字串的行. 應用 '[^g]oo' 作搜尋字串,^

符號如果出現[]的起始位置表示否定,但是[]的其他位置是普通字元。[^ab^c] 除了a或b或^或c的其他任意單個字元

5、* 用於修飾前導字元,表示前導字元出現0或任意多

如:'a*grep'匹配所有0個或多個a後緊跟grep的行。.*”表示任意字串

6、\? 用於修飾前導字元,表示前導字元出現0或1

a\? 匹配0或1個a

7、\+ 用於修飾前導字元,表示前導字元出現1或多

a\+ 匹配1或多個a

8、\{n,m\}  用於修飾前導字元,表示前導字元出現n至m次 (n和m都是整數,且n<m)

a\{3,5\} 匹配3至5個連續的a

\{n,m\}還有其他幾種形式:

\{n\}  連續的n

前導字元

\{n,\}  連續的至少n個前導字元

9、\  用於轉義緊跟其後的單個特殊字元,使該特殊字元成為普通字元

如:^\.[0-9][0-9]以一個句點和兩個數字開始

例如:

a* 匹配連續的任意(也包括0)個a

a\? 匹配0或1個a

a\+ 匹配1或多個a

a\{3,5\} 匹配3至5個連續的a

\.* 匹配0或多個連續的. \.表示普通字元句點

10、|表示  如: a|b|c 匹配a或b或c。如:grep|sed匹配grep或sed

11、(),將部分內容合成一個單位組,比如 要搜尋 glad good 可以如下 'g(la|oo)d'

綜合舉例

1 Christian Scott lives here and will put ona Christmas party.

2 There are around 30 to 35 people invited.

3 They are:

4  Tom

5 Dan

6 Rhonda Savage

7 Nicky and Kimerly.

8 Steve, Suzanne, Ginger and Larry. 

^[A-Z]..$

搜尋行以A至Z的一個字母開頭,然後跟兩個任意字母,然後跟一個換行符的行。將找到第5行。

^[A-Z][a-z]*3[0-5]
搜尋以一個大寫字母開頭,後跟0個或多個小寫字母,再跟數字3,再跟05之間的一個數字。無法找到匹配行

(改成^[A-Z][a-z]*.*3[0-5]可找到第2行)

^[A-Z][a-z]*.*3[0-5]
^ *[A-Z][a-z][a-z]$

搜尋以0個或多個空格開頭,跟一個大寫字母,兩個小寫字母和一個換車符。將找到第4行的TOM(整行匹配)和第5行。注意,*前面有一個空格

^[A-Za-z]*[^,][A-Za-z]*$

將查詢以0個或多個大寫或小寫字母開頭,不跟逗號,然後跟0個或多個大寫或小寫字母,然後跟一個換車符。將找到第4和5行。

# ls -l  /bin | grep  '^...s'

上面的命令是用來查詢suid檔案的;

# ls -lR /usr | grep   '^...s..s'

上面的命令是用來查詢suidguid的。


二、grep命令的用法


簡介:

grep (global search regular expression(RE) and print out the line,全面搜尋正則表示式並把行打印出來)是一種強大的文字搜尋工具,它能使用正則表示式搜尋文字,並把匹配的行打印出來.

引數:

1. -ANUM,--after-context=NUM   除了列出符合行之外,並且列出後NUM行。

:   $ grep –A1 panda file  (file中搜尋有panda樣式的行,並顯示該行的後1)

[[email protected] ~]# grep -A 1 panda a.txt 

2. -BNUM,--before-context=NUM  與-A NUM 相對,但這此引數是顯示除符合行之外並顯示在它之前的NUM行。如:    (從file中搜尋有panda樣式的行,並顯示該行的前1行)

$ grep -B 1 panda file

[[email protected] ~]# grep -B 1 panda a.txt 


3、 -C[NUM], -NUM, --context[=NUM]  列出符合行之外並列出上下各NUM行,預設值是2。

 如:   (列出file中除包含panda樣式的行外並列出其上下2行)(若要改變預設值,直接改變NUM即可)

$ grep -C[NUM] panda file

4、 -c, --count  不顯示符合樣式行,只顯示符合的總行數。若再加上-v,--invert-match,引數顯示不符合的總行數

5、-i,--ignore-case 忽略大小寫差別

6、-n,--line-number 在匹配的行前面列印行號

 7、-v,--revert-match  反檢索,只顯示不匹配的行

8、精確匹配:

例如在抽取字串“ 48”,返回結果包含諸如484和483等包含“48”的其他字串,實際上應精確抽取只包含48的各行。

使用grep抽取精確匹配的一種有效方式是在抽取字串後加\>。假定現在精確抽取48,

方法如下:


9、-s 不顯示不存在或無匹配文字的錯誤資訊

如:執行命令grep "root" /etc/password,因為password檔案不存在,所以在螢幕上輸出錯誤資訊,若使用grep命令-s開關,可遮蔽錯誤資訊


要用好grep這個工具,其實就是要寫好正則表示式,所以這裡不對grep的所有功能進行例項講解,只列幾個例子,講解一個正則表示式的寫法。

[[email protected] ~]#  ls -l | grep  '^d' 
grep  'test'  d* 

顯示所有以d開頭的檔案中包含test的行。

[[email protected] ~]# grep  'test'  aa  bb  cc 

顯示在aa,bb,cc檔案中匹配test的行。



[[email protected] ~]# grep  '[a-z]\{5,\}'  aa 

顯示所有包含每個字串至少有5個連續小寫字元的字串的行。

[[email protected] ~]# grep  't[a|e]st'  a.txt 

顯示包含test或tast的所有行。


[[email protected] ~]# grep  '\.$'  a.txt 

顯示以.為結尾的所有行。

三、sed命令的用法

sed是一種線上編輯器,它一次處理一行內容。處理時,把當前處理的行儲存在臨時緩衝區中,稱為“模式空間”(pattern space),接著用sed命令處理緩衝區中的內容,處理完成後,把緩衝區的內容送往螢幕。接著處理下一行,這樣不斷重複,直到檔案末尾。檔案內容並沒有改變,除非你使用重定向儲存輸出。

sed的基本命令:

1.替換: s命令

1.1 基本用法

  如: sed 's/test/dsdada/'<old >new
  該例子將檔案 a.txt 中的每一行第一次出現的 test 替換成 dsdada, 將結果輸出到檔案 kang.txt

[roo[email protected] ~]# sed 's/test/dsdada/'< a.txt >kang.txt

  s            " 替換 " 命令 
  /../../      分割符 (Delimiter)
  day          搜尋字串 
  night        替換字串 

  其實 , 分割符 "/" 可以用別的符號代替 , 比如 ",","|" 等 .

 如:sed's/\/usr\/local\/bin/\/common\/bin/'<old >new

[[email protected] ~]# sed 's/\/usr\/local\/bin/\/common\/bin/'<a.txt >aa


  等價於 sed 's_/usr/local/bin_/common/bin_' <old >new
[[email protected] ~]# sed 's_/common\/bin_/usr/local/bin_'<a.txt >aa


  顯然 , 此時用 "_" 作分割符比 "/" 好得多

1.2 用 & 表示匹配的字串

有時可能會想在匹配到的字串周圍或附近加上一些字元 .
 如: sed 's/abc/(abc)/' <old >new

[[email protected] ~]# sed 's/panda/(panda)/' <a.txt>aa

該例子在找到的 abc 前後加上括號 .

該例子還可以寫成 sed 's/abc/(&)/' <old >new

[[email protected] ~]# sed 's/panda/(&)/' <a.txt >kang.txt 

 下面是更復雜的例子 :

[[email protected] ~]# sed 's/[a-z]*/(&)/' <a.txt >kang.txt 

sed 預設只替換搜尋字串的第一次出現 , 利用 /g 可以替換搜尋字串所有

[[email protected] ~]# sed 's/panda/mytest/g' a.txt 

在整行範圍內把panda替換為mytest。如果沒有g標記,則只有每行第一個匹配的test被替換成mytest。

$ sed's/^192.168.0.1/&localhost/' a.txt-----&符號表示替換字串中被找到的部份。所有以192.168.0.1開頭的行都會被替換成它自已加 localhost,變成192.168.0.1localhost。

[[email protected] ~]# sed 's/^192.168.0.1/&localhost/' a.txt 

$ sed 's#10#100#g' a.txt-----不論什麼字元,緊跟著s命令的都被認為是新的分隔符,所以,“#”在這裡是分隔符,代替了預設的“/”分隔符。表示把所有10替換成100。

[[email protected] ~]# sed 's#48#100#g' a.txt


如果需要對同一檔案或行作多次修改,可以使用 "-e" 選項

[[email protected] ~]# sed -e '1,3s/c/h/' -e 's/There/bbb/' a.txt 

取得eth0網絡卡IP地址:


2.刪除行:d命令

從某檔案中刪除包含"Nicky" 的所有行

[[email protected] ~]# sed 'Nicky d' a.txt 

將/etc/passwd的內容顯示並列印行號,同時將2~5刪除

[[email protected] ~]# nl /etc/passwd | sed '2,5d'

附:nl命令在linux系統中用來計算檔案中行號。nl可以將輸出的檔案內容自動的加上行號

如果只要刪除第2行,可以使用nl /etc/passwd |sed '2d' 來達成,至於若是要刪除第 3 到最後一行,則是nl /etc/passwd | sed '3,$d'的啦。

3.增加行:a命令(在指定的行後新增)或i命令(在指定的行前新增)

a的後面可以接字串,而這些字串會在新的一行出現

在/etc/passwd的第二行後增加“XXXXX”字樣的新行

[[email protected] ~]# nl /etc/passwd | sed '2a hello'

在/etc/passwd的第二行前增加“XXXXX”字樣的新行

[[email protected] ~]# nl /etc/passwd | sed '2i hello'

如果要同時新增多行,則每行之間要用反斜槓\來進行新行的新增

[r[email protected] ~]# nl /etc/passwd | sed '2a hello \
> how are you ? \
> my is kangshuo \
> zhen zi dan'

4、取代行:c命令

c的後面可以接字串,這些字串可以取代n1,n2之間的行

[[email protected] ~]# nl  /etc/passwd | sed '2,5c  no 2-5 number.' 

5、列印:p命令

sed '/north/p' a.txt 預設輸出所有行,找到test的行重複列印

[[email protected] ~]# sed '/test/p' a.txt 

sed n '/north/p' a.txt禁止預設輸出,只打印找到test的行


nl  /etc/passwd | sed -n '5,7p' 僅列出/etc/passwd檔案中的第57行內容

[[email protected] ~]# nl  /etc/passwd | sed -n '5,7p'

注:sed-i選項可以直接修改檔案中的內容

[[email protected] ~]# sed -i '2i hello' a.txt 

6.擴充套件:

呼叫sed有三種方式:

在命令列鍵入命令

sed命令插入指令碼檔案,然後呼叫sed

sed命令插入指令碼檔案,並使sed指令碼可執行。

A、 使用sed命令列格式為:

sed [選項]sed命令 輸入檔案。

記住在命令列使用sed命令時,實際命令要加單引號。sed也允許加雙引號。

B、使用sed指令碼檔案,格式為:

sed [選項]-f sed指令碼檔案  輸入檔案

C、要使用第一行具有sed命令直譯器的sed指令碼檔案,其格式為:

sed指令碼檔案 [選項]  輸入檔案

不管是使用shell命令列方式或指令碼檔案方式,如果沒有指定輸入檔案,sed從標準輸入中接受輸入,一般是鍵盤或重定向結果。

sed選項如下:

-f, --filer=script-file 引導sed指令碼檔名

綜合舉例:

通過sed指令碼對a.txt進行處理,a.txt檔案內容如下:


建立sed指令碼檔案append.sed,通過sed指令碼向a.txt中新增內容,指令碼內容如下:

[[email protected] ~]# vim append.sed
內容如下:
#!/bin/sed -f
/company/ a\
hello.\
then suddenly it happened .

儲存它,增加可執行許可權:chmod +x append.sed

[[email protected] ~]# chmod +x append.sed

執行指令碼append.sed

顯示結果如下:


現在檢視其具體功能。

第一行是sed命令解釋行。指令碼在這一行查詢sed以執行命令,這裡定位在/bin。

第二行以/company/開始,這是附加操作起始位置。a\通知sed這是一個附加操作,首先應插入二個新行。

第三、四行是附加操作要加入到拷貝的實際文字。

這裡只舉例通過sed指令碼增加新行的操作,有關sed的其他操作大家要會舉一反三。

四、printf命令:


printf是一個把從標準輸入的字元按照你所要求的格式輸出到標準輸出即螢幕的命令. 在很多時候,我們可能需要將自己的資料給他格式化輸出的。例如考試分數的輸出:假設有一個檔案kang.txt記錄著考試分數,內容如下圖所示:

上表的資料主要分成五個欄位,各個欄位之間可使用 tab 或空格鍵進行分隔。

printf命令格式:
printf 	'列印格式' 	實際內容

關於格式方面的幾個特殊樣式

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

例如1:下列命令是以整數形式輸出23並換行;以字串形式輸出hello並換行.

[[email protected] ~]# printf  "this is a integer:%i\nthis is string:%s\n" 23 "hello"

例如2:下列命令是以4位整數形式輸出23並換行;以7位字串形式輸出hello並換行.

[[email protected] ~]# printf  "this is a integer:%4i\nthis is string:%7s\n" 23 "hello"

例如3:

參考底下這個範例
[[email protected] ~]# printf '%s\t %s\t %s\t %s\t %s\t \n' $(cat kang.txt)

如上所示,printf命令的輸出結果並沒有對齊,%s代表一個不固定長度的字串,而字串與字串中間就以 \t 這個 [tab] 分隔符來處理。既然每個欄位的長度不固定會造成上述的困擾,那我將每個欄位固定就好啦。

將kang.txt檔案中的內容,分別以字串、整數、小數點來顯示:

[[email protected] ~]# printf '%10s %5i %5i %5i %8.2f \n' $(cat kang.txt | grep -v Name)

上面的格式共分為五個欄位, %10s 代表的是一個長度為 10 個字元的字串欄位,%5i 代表的是長度為 5 個字元的數字欄位,至於那個 %8.2f 則代表長度為 8 個字元的具有小數點的欄位,其中小數點有兩個字元寬度;全部的寬度僅有 8 個字元,整數部分佔有 5 個字元,小數點本身 (.) 佔一位,小數點後的位數則有兩位。

printf 除了可以格式化處理之外,他還可以依據ASCII 的數字與字元對應來顯示資料,舉例來說 16 進位的 55 可以得到什麼 ASCII 的顯示字元?


五、awk命令:


awk也是一個數據處理工具!相較於 sed 常常作用於一整個行的處理, awk 則比較傾向於一行當中分成數個欄位來處理。

.awk語言的最基本功能是在檔案或字串中基於指定規則來分解抽取資訊,也可以基於指定的規則來輸出資料。

 有三種方式呼叫awk

1.命令列方式

awk  [-F field-separator]  'commands' input-files

其中,[-F域分隔符]是可選的,因為awk使用空格或tab鍵作為預設的域分隔符,因此如果要瀏覽域間有空格的文字,不必指定這個選項,如果要瀏覽諸如passwd檔案,此檔案各域以冒號作為分隔符,則必須指明-F選項,如:awk -F: 'commands' input-file。

注意:在linux系統中用環境變數IFS儲存分隔符,但根據實際應用也可以改變IFS的值.

例如:

指令碼執行結果如下:


commands 是真正awk命令, input-files 是待處理的檔案。

iput_files可以是多於一個檔案的檔案列表,awk將按順序處理列表中的每個檔案。

在awk中,檔案的每一行中,由域分隔符分開的每一項稱為一個域。通常,在不指名-F域分隔符的情況下,預設的域分隔符是空格或tab鍵。

2.shell指令碼方式

將所有的awk命令插入一個檔案,並使awk程式可執行,然後awk命令直譯器作為指令碼的首行,以便通過鍵入指令碼名稱來呼叫。

相當於shell指令碼首行的:#!/bin/sh可以換成:#!/bin/awk

3.將所有的awk命令插入一個單獨檔案,然後呼叫:

Awk   -f   awk-script-file         input-files

其中,-f選項載入awk-script-file中的awk指令碼,input-files跟上面的是一樣的。

awk的模式和動作

任何awk語句都由模式和動作組成(awk_pattern { actions })。
在一個awk指令碼中可能有許多語句。

模式部分決定動作語句何時觸發及觸發事件。處理即對資料進行的操作。如果省略模式部分,動作將時刻保持執行狀態。即省略時不對輸入記錄進行匹配比較就執行相應的actions。

模式可以是任何條件語句或正則表示式等。awk_pattern可以是以下幾種型別:

(1.)正則表示式用作awk_pattern:/regexp/

例如: awk '/^[a-z]/' input_file

(2.)布林表示式用作awk_pattern,表示式成立時,觸發相應的actions執行。

① 表示式中可以使用變數(如欄位變數$1,$2等)和/regexp/

② 布林表示式中的操作符:

關係操作符: <> <= >= == !=
匹配操作符: value ~ /regexp/ 如果value匹配/regexp/,則返回真
value!~ /regexp/ 如果value不匹配/regexp/,則返回真

例如: awk '$2 > 10 {print "ok"}' input_file

  awk '$3 ~ /^d/ {print"ok"}' input_file

③ &&(與) 和 ||(或) 可以連線兩個/regexp/或者布林表示式,構成混合表示式。!(非) 可以用於布林表示式或者/regexp/之前。

例如: awk '($1< 10 ) && ($2 > 10) {print "ok"}' input_file 

         awk '/^d/ || /x$/ {print"ok"}' input_file

模式包括兩個特殊欄位 BEGIN和END。使用BEGIN語句設定計數和列印頭。BEGIN語句使用在任何文字瀏覽動作之前,之後文字瀏覽動作依據輸入文字開始執行。END語句用來在awk完成文字瀏覽動作後列印輸出文字總數和結尾狀態標誌。

實際動作在大括號{ }內指明。動作大多數用來列印,但是還有些更長的程式碼諸如i f和迴圈語句及迴圈退出結構。如果不指明採取動作,awk將打印出所有瀏覽出來的記錄。

awk執行時,其瀏覽域標記為$1,$2...$n。這種方法稱為域標識。使用這些域標識將更容易對域進行進一步處理。

使用$1 , $3表示參照第1和第3域,注意這裡用逗號做域分隔。如果希望列印一個有5個域

的記錄的所有域,不必指明$1 , $2 , $3 , $4 , $5,可使用$0,意即所有域。

為列印一個域或所有域,使用print命令。這是一個awk動作

awk的執行過程:

① 如果BEGIN 區塊存在,awk執行它指定的actions。

②  awk從輸入檔案中讀取一行,稱為一條輸入記錄。(如果輸入檔案省略,將從標準輸入讀取)

③  awk將讀入的記錄分割成欄位,將第1個欄位放入變數$1中,第2個欄位放入$2,以此類推。$0表示整條記錄。

④  把當前輸入記錄依次與每一個awk_cmd中awk_pattern比較,看是否匹配,如果相匹配,就執行對應的actions。如果不匹配,就跳過對應的actions,直到比較完所有的awk_cmd。

⑤  當一條輸入記錄比較了所有的awk_cmd後,awk讀取輸入的下一行,繼續重複步驟③和④,這個過程一直持續,直到awk讀取到檔案尾。

⑥  當awk讀完所有的輸入行後,如果存在END,就執行相應的actions。

入門例項:

例1:顯示/etc/passwd檔案中的使用者名稱和登入shell 

[[email protected] ~]# awk -F : '{print $1,$7}'  /etc/passwd

如果只是顯示/etc/passwd的賬戶和賬戶對應的shell,而賬戶與shell之間以tab鍵分割

[[email protected] ~]# awk -F : '{print $1 "\t" $7}'  /etc/passwd

如果只是顯示/etc/passwd檔案中的使用者名稱和登入shell, 而賬戶與shell之間以逗號分割

[[email protected] ~]# awk -F : '{print $1 "," $7}'  /etc/passwd

注:awk的總是輸出到標準輸出,如果想讓awk輸出到檔案,可以使用重定向。

例2:顯示/etc/passwd檔案中的UID大於500的所有使用者的使用者名稱和登入shell

[[email protected] ~]# awk -F : '$3>500{print $1,$7}' /etc/passwd

例3:如果只是顯示/etc/passwd檔案中的UID大於500的使用者名稱和登入shell,而賬戶與shell之間以逗號分割,

而且在所有行新增列名name,shell,在最後一行新增"blue,/bin/nosh"。

[[email protected] ~]# awk -F : 'BEGIN {print "name,shell"} $3>500 {print $1","$7} END {print "blue,/bin/bash"}' /etc/passwd

注意:

1.awk 後面接兩個單引號並加上大括號 {} 來設定想要對資料進行的處理動作

2.awk工作流程是這樣的:先執行BEGING,然後讀取檔案,讀入有\n換行符分割的一條記錄,

然後將記錄按指定的域分隔符劃分域,填充域,$0則表示所有域,$1表示第一個域,$n表示第n個域,隨後開始執行模式所對應的動作。

接著開始讀入第二條記錄······直到所有的記錄都讀完,最後執行END操作。

思考題:如何列印所有記錄(以/etc/passwd中的內容為例)

[[email protected] ~]# awk '{print $0}' /etc/passwd

例4:搜尋/etc/passwd有root關鍵字的所有行

[[email protected] ~]# awk -F : '/root/' /etc/passwd

這種是pattern(模式)的使用示例,匹配了pattern(這裡是root)的行才會執行action(沒有指定action,預設輸出每行的內容)。

搜尋支援正則表示式,例如找root開頭的:

[[email protected] ~]# awk -F : '/^root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
[[email protected] ~]# 

搜尋/etc/passwd有root關鍵字的所有行,並顯示對應的shell

[[email protected] ~]# awk  -F : '/root/ {print $7}' /etc/passwd

這裡指定了action是{print $7}

例5:顯示最近登入系統的5個使用者資訊,只顯示使用者名稱和IP地址

使用last命令可以檢視最近登入的使用者資訊。如下圖所示:

[[email protected] ~]# last -n 5

使用awk命令抽取使用者名稱和IP區域的資料

[[email protected] ~]# last -n 5 | awk '{print $1,$3}'

[[email protected] ~]# last -n 5 | awk '{print $1 "\t" $3}'

awk內建變數

awk有許多內建變數用來設定環境資訊,下面給出了最常用的一些變數。

 FILENAME awk瀏覽的檔名

 FS   設定輸入域分隔符,等價於命令列-F選項

 NF   瀏覽記錄的域個數(每一行($0)擁有的欄位總數)

 NR   已讀的記錄數(awk所處理的是第幾行資料)

例6:統計/etc/passwd:檔名,每行的行號,每行的列數,對應的完整行內容:

[[email protected] ~]# awk -F : '$3>500 {print "filename:" FILENAME ",linenumber:" NR ",columns:" NF ",linecontent:" $0 }' /etc/passwd


顯示所有賬戶的記錄,並帶有其記錄號,並在END部分列印輸入檔名

[[email protected] ~]# awk -F : '{print NF,NR,$0} END {print FILENAME}' /etc/passwd

除了awk的內建變數,awk還可以自定義變數

例7:統計/etc/passwd的賬戶人數

[[email protected] ~]# awk  '{count++;print $0;} END {print "user count is:",count}' /etc/passwd

count是自定義變數。之前的action{}裡都是隻有一個print,其實print只是一個語句,而action{}可以有多個語句,以;號隔開。

這裡沒有初始化count,雖然預設是0,但是妥當的做法還是初始化為0:

[[email protected] ~]# awk 'BEGIN {count=0; print "[start]user count is:", count} {count=count+1;print $0;} END {print "[end]user count is:", count}' /etc/passwd

例8:統計某個資料夾下的檔案佔用的位元組數

[[email protected] ~]# ls -l /etc/ | awk 'BEGIN {size=0;} {size=size+$5;} END {print "[end]size is:", size}'


如果以M為單位顯示:

[[email protected] ~]# ls -l /etc/ | awk 'BEGIN {size=0;} {size=size+$5;} END {print "[end]size is:", size/1024/1024,"M"}' 


注意:以上統計沒有包括子目錄中的檔案。

如果想快速檢視所有檔案的長度及其總和,但要排除子目錄,如何實現:

[[email protected] ~]# ls -l nginx-1.10.2 | awk '/^[^d]/ {print $9 "\t" $5;sum+=$5} END {print "total KB:" sum}'


六、函式及指令碼的綜合應用

1shell函式:shell允許將一組命令集或語句形成一個可用塊,這些塊稱為shell函式。

函式由兩部分組成:函式標題、函式體。

標題是函式名。函式體是函式內的命令集合。

標題名應該唯一;如果不是,將會混淆結果,因為指令碼在檢視呼叫指令碼前將首先搜尋函式呼叫相應的shell

2定義函式的格式為:

函式名(){

命令1

...

}

如果願意,可在函式名前加上關鍵字function,這取決於使用者。

function函式名()

{

命令1

  ...

}

3、舉例:

例1:刪除檔案中的空行

這個指令碼(指令碼名為del.lines)可以處理一個或