天天看點

自動化運維工程師必備的shell腳本知識

部落客QQ:819594300

有什麼疑問的朋友可以聯系部落客,部落客會幫你們解答,謝謝支援!一、正規表達式:

正規表達式(或稱Regular Expression,簡稱RE)就是由普通字元(例如字元 a 到 z)以及特殊字元(稱為元字元)組成的文字模式。

該模式描述在查找文字主體時待比對的一個或多個字元串。

正規表達式作為一個模闆,将某個字元模式與所搜尋的字元串進行比對。簡單的說,正規表達式就是處理字元串的方法,它是以行為機關來進行字元串的處理行為,正規表達式通過一些特殊符号的輔助,可以讓使用者輕易的達到搜尋/删除/取代某特定字元串的處理程式。vim、grep、find、awk、sed等指令都支援正規表達式。

常用正規表達式:

<a href="https://s3.51cto.com/wyfs02/M00/8F/7E/wKioL1jh9faTd3hVAAPJhABehwE371.jpg" target="_blank"></a>

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]比對任意英文字母或數字之一

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

5、[^…] 可以用^标記做[]内的字首,表示除[]内的字元之外的其他字元(即比對不在此括号中的任何字元)。比如搜尋oo前沒有g的字元串的行.應用 '[^g]oo' 作搜尋字元串,^符号如果出現在[]的起始位置表示否定,但是在[]的其他位置是普通字元。

例如  [^ab^c] 除了a或b或^或c的其他任意單個字元

<a href="https://s5.51cto.com/wyfs02/M01/8F/7E/wKioL1jh9fbA9929AAJJil7bo8c178.jpg" target="_blank"></a>

6、* 用于修飾前導字元,表示前導字元出現0次或任意多次

例如  'a*grep'比對所有0個或多個a後緊跟grep的行。

特殊用法:  .*表示任意字元串

7、\? 用于修飾前導字元,表示前導字元出現0或1次

例如  a\? 比對0或1個a

8、\+ 用于修飾前導字元,表示前導字元出現1或多次

例如  a\+ 比對1或多個a

9、\{n,m\}  用于修飾前導字元,表示前導字元出現n至m次 (n和m都是整數,且n&lt;m)

例如 a\{3,5\} 比對3至5個連續的a

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

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

例如 a\{3\}  表示比對3個連續的a

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

<a href="https://s4.51cto.com/wyfs02/M01/8F/80/wKiom1jh9feQcaOFAAGQwjcooYs571.jpg" target="_blank"></a>

例如  a\{3,\}  表示比對至少3個連續的a

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

例如    ^\.[0-9][0-9]  表示以一個句号和兩個數字開頭的

上述正規表達式用法示例:

a*比對連續的任意(也包括0)個a

a\?比對0或1個a

a\+比對1或多個a

a\{3,5\}比對3至5個連續的a

\.*比對0或多個連續的. \.表示普通字元句号

11、| 表示或

 例如  a|b|c 比對a或b或c 

例如  grep|sed比對grep或sed

注意:當“|” 前後是兩個指令語句的時候,這時候“|”就是管道符号,而不是表示或

12、() 表示将部分内容合成一個機關組

例如   要搜尋 glad 或 good 可以如下 'g(la|oo)d'

<a href="https://s4.51cto.com/wyfs02/M01/8F/7E/wKioL1jh9ffjeugbAAHJGQsQ2MM467.jpg" target="_blank"></a>

綜合舉例1:

<a href="https://s4.51cto.com/wyfs02/M02/8F/80/wKiom1jh9ffRX3PxAAArxsWBBxY726.jpg" target="_blank"></a>

<a href="https://s3.51cto.com/wyfs02/M02/8F/80/wKiom1jh9fii6jx8AACS6ZDMGHw016.jpg" target="_blank"></a>

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

<a href="https://s3.51cto.com/wyfs02/M02/8F/7E/wKioL1jh9fjC7zMIAABGeQG4mvw985.jpg" target="_blank"></a>

②搜尋以一個大寫字母開頭,後跟0個或多個小寫字母,再跟數字3,再跟0—5之間的一個數字。無法找到比對行(改成^[A-Z][a-z]*.*3[0-5]可找到第2行)。

<a href="https://s3.51cto.com/wyfs02/M00/8F/80/wKiom1jh9fiDuwvPAACfxE2a-wQ964.jpg" target="_blank"></a>

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

<a href="https://s3.51cto.com/wyfs02/M02/8F/7E/wKioL1jh9fjRwnaMAABR2XcFLlk944.jpg" target="_blank"></a>

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

<a href="https://s1.51cto.com/wyfs02/M00/8F/80/wKiom1jh9fnyv-9BAABItF6Z-os552.jpg" target="_blank"></a>

綜合舉例2:

下面的指令是用來查找suid檔案的:

<a href="https://s1.51cto.com/wyfs02/M00/8F/7E/wKioL1jh9fmBTfwYAAA7P7pnrXo984.jpg" target="_blank"></a>

下面的指令是用來查找suid和guid的:

<a href="https://s1.51cto.com/wyfs02/M00/8F/7E/wKioL1jh9fminDhfAAA6oFhaY4Q298.jpg" target="_blank"></a>

二、grep指令的用法

grep(global search regular expression(RE) and print out the line,全面搜尋正規表達式并把行列印出來)是一種強大的文本搜尋工具,它能使用正規表達式搜尋文本,并把比對的行列印出來.

<a href="https://s3.51cto.com/wyfs02/M01/8F/80/wKiom1jh9fqQ_dfWAAMOm6AubUk266.jpg" target="_blank"></a>

參數:

1.-A  number,--after-context=number   除了列出符合行之外,并且列出後number行。

例如 $ grep –A 1 pandafile  (從file中搜尋有panda樣式的行,并顯示該行的後1行)

例如:

<a href="https://s3.51cto.com/wyfs02/M01/8F/7E/wKioL1jh9fuiO4c7AADoKAWWy2g659.jpg" target="_blank"></a>

2.-B number,--before-context=number  與 -A number 相對,但這此參數是顯示除符合行之外并顯示在它之前的m=number行。例如  (從file中搜尋有panda樣式的行,并顯示該行的前1行)

$grep -B 1 panda file

<a href="https://s5.51cto.com/wyfs02/M02/8F/80/wKiom1jh9fuAU4HZAACH8IcKrKU575.jpg" target="_blank"></a>

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

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

$grep -C[NUM] panda file

<a href="https://s5.51cto.com/wyfs02/M02/8F/7E/wKioL1jh9fuglXjpAAChbNLMJCE391.jpg" target="_blank"></a>

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

<a href="https://s5.51cto.com/wyfs02/M01/8F/80/wKiom1jh9fywiR57AABg3zBnPXM831.jpg" target="_blank"></a>

<a href="https://s5.51cto.com/wyfs02/M01/8F/7E/wKioL1jh9fygObUhAADfesOUePU557.jpg" target="_blank"></a>

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

<a href="https://s5.51cto.com/wyfs02/M00/8F/80/wKiom1jh9fySIsBZAAEw9bHu-b8760.jpg" target="_blank"></a>

6、-n,--line-number在比對的行前面列印行号

<a href="https://s5.51cto.com/wyfs02/M02/8F/80/wKiom1jh9f3z4V5lAAB3E9csrnc357.jpg" target="_blank"></a>

7、-v,--revert-match  反檢索,隻顯示不比對的行

<a href="https://s2.51cto.com/wyfs02/M00/8F/7E/wKioL1jh9f3jTiioAAB2yAiqSBQ610.jpg" target="_blank"></a>

8、精确比對:

例如在抽取字元串“ 48”,傳回結果包含諸114826和45648368等包含“48”的其他字元串,實際上應精确抽取隻包含48的各行。

使用grep抽取精确比對的一種有效方式是在抽取字元串前加\&lt;,後加\&gt;。假定現在精确抽取48,

方法如下:

#grep'\&lt;48\&gt;' filename

<a href="https://s2.51cto.com/wyfs02/M02/8F/7E/wKioL1jh9f3xccBpAAFzJL-JzB4158.jpg" target="_blank"></a>

9、-s不顯示不存在或無比對文本的錯誤資訊

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

<a href="https://s2.51cto.com/wyfs02/M00/8F/80/wKiom1jh9f7Rp-49AADdp0j8SQM565.jpg" target="_blank"></a>

總結:要用好grep這個工具,其實就是要寫好正規表達式,是以這裡不對grep的所有功能進行執行個體講解,隻列幾個例子,講解一個正規表達式的寫法

①ls -l | grep  '^d'

通過管道過濾ls -l輸出的内容,隻顯示以d開頭的行。

②ls -l | grep  'test' d*

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

③ls -l | grep  'test' aa  bb  cc

顯示在aa,bb,cc檔案中比對test的行

④ls -l | grep  '[a-z]\{5,\}' aa

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

⑤ls -l | grep  ‘t[a|e]st’ filename

顯示包含test或tast的所有行

⑥grep  '\.$' filename

顯示以.為結尾的所有行

三、sed指令的用法

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

即不帶“-i”選項的sed指令都是沒有實際修改檔案内容,或者你可以重定向輸出。

sed的指令格式:

<a href="https://s4.51cto.com/wyfs02/M01/8F/80/wKiom1jh9f7he8yoAABtdWSbm8A464.jpg" target="_blank"></a>

Sed選項:

<a href="https://s4.51cto.com/wyfs02/M00/8F/7E/wKioL1jh9f_BIKQzAAELWyVZfz4235.jpg" target="_blank"></a>

Sed指令:

<a href="https://s4.51cto.com/wyfs02/M01/8F/7E/wKioL1jh9f-QU8xlAAMujSubk8Y515.jpg" target="_blank"></a>

sed的基本指令:

1.替換指令“s”

1.1基本用法

如: sed  's/day/night/'   old檔案  &gt;  new檔案

  該例子将檔案 old 中的每一行第一次出現的 day 替換成 night, 将結果輸出到檔案 new

解釋:

s          " 替換 " 指令

  /../../     分割符 (Delimiter)

  day         搜尋字元串(即原字元串)

  night       替換字元串(即新字元串)

  其實 , 分割符 "/" 可以用别的符号代替 , 比如 ","  "|"  “_” 等

 如:sed  's/\/usr\/local\/bin/\/common\/bin/'  old  &gt;new

  等價于 sed  's_/usr/local/bin_/common/bin_'   old  &gt;new

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

用 &amp; 表示比對的字元串

有時可能會想在比對到的字元串周圍或附近加上一些字元 .

 如: sed   's/abc/(abc)/'   old  &gt;  new

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

 該例子還可以寫成 sed   's/abc/(&amp;)/'   old   &gt;  new

下面是更複雜的例子 :

 sed    's/[a-z]*/(&amp;)/' old  &gt;  new

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

#sed 's/test/mytest/g'  example-----在整行範圍内把test替換為mytest。如果沒有g标記,則隻有每行第一個比對的test被替換成mytest。

#sed  's/^192.168.0.1/&amp;localhost/'  example-----&amp;符号表示替換字元串中被找到的部份。所有以192.168.0.1開頭的行都會被替換成它自已加 localhost,變成192.168.0.1localhost。

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

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

<a href="https://s1.51cto.com/wyfs02/M02/8F/81/wKiom1jh-IzDQnMhAAAnQzeaMMw063.jpg" target="_blank"></a>

取得eno16777736網卡IP位址:

<a href="https://s4.51cto.com/wyfs02/M02/8F/7E/wKioL1jh9gDwCcskAAEsOY1pgyw157.jpg" target="_blank"></a>

2.删除行指令“d”

例子1:從某檔案中删除包含 "how" 的所有行

<a href="https://s4.51cto.com/wyfs02/M00/8F/80/wKiom1jh9gDAduqkAABFfOFinuY594.jpg" target="_blank"></a>

例子2:将/etc/passwd的内容顯示并找印行号,同時将2~5删除

<a href="https://s4.51cto.com/wyfs02/M00/8F/7E/wKioL1jh9gGg7bTjAAD4npv-rck111.jpg" target="_blank"></a>

解釋如下:

nl指令在linux系統中用來計算檔案中行号。nl 可以将輸出的檔案内容自動的加上行号

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

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

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

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

<a href="https://s4.51cto.com/wyfs02/M01/8F/80/wKiom1jh9gHDqKh6AADZCMVqRPo851.jpg" target="_blank"></a>

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

<a href="https://s4.51cto.com/wyfs02/M01/8F/7E/wKioL1jh9gHBdOKFAADO2prz2bI028.jpg" target="_blank"></a>

例子3:如果要同時新增多行,則每行之間要用反斜杠\來進行新行的添加

<a href="https://s4.51cto.com/wyfs02/M01/8F/80/wKiom1jh9iSh1mrPAAEV5GSifUI461.jpg" target="_blank"></a>

4、取代行指令“c”

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

<a href="https://s4.51cto.com/wyfs02/M01/8F/7E/wKioL1jh9iTR0KlHAADwwQOuOPQ758.jpg" target="_blank"></a>

5、列印指令“p”

例子1:

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

例子2:

sed  –n '/north/p' datafile 禁止預設輸出,隻列印找到north的行

例子3:

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

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

<a href="https://s3.51cto.com/wyfs02/M02/8F/80/wKiom1jh9iXhYsKGAAERlf_6woY629.jpg" target="_blank"></a>

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腳本對test.txt進行處理,test.txt檔案内容如下:

<a href="https://s4.51cto.com/wyfs02/M02/8F/80/wKiom1jh9iXSR5MyAACLy8HPuzQ815.jpg" target="_blank"></a>

建立sed腳本檔案append.sed,通過sed腳本向test.txt中新增内容,腳本内容如下:

<a href="https://s4.51cto.com/wyfs02/M02/8F/7E/wKioL1jh9ibz6aVyAABWEo8ttUQ848.jpg" target="_blank"></a>

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

<a href="https://s4.51cto.com/wyfs02/M00/8F/80/wKiom1jh9ibyl9gPAAAxsq_c5KM886.jpg" target="_blank"></a>

顯示結果如下:

<a href="https://s5.51cto.com/wyfs02/M00/8F/7E/wKioL1jh9ieCEElKAACwUMhs9GI525.jpg" target="_blank"></a>

檢視其具體功能:

第一行是sed指令解釋行。腳本在這一行查找sed以運作指令,這裡定位在/bin。

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

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

這裡隻舉例通過sed腳本增加新行的操作,有關sed的其他操作大家要會舉一反三。

四、printf指令:

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

<a href="https://s3.51cto.com/wyfs02/M01/8F/80/wKiom1jh9ifD-KC5AABfMuhEmYU824.jpg" target="_blank"></a>

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

printf指令格式:

printf     '列印格式'    實際内容

關于格式方面的幾個特殊樣式:

<a href="https://s5.51cto.com/wyfs02/M01/8F/7E/wKioL1jh9iih2nYoAAOlV-brHuc131.jpg" target="_blank"></a>

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

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

<a href="https://s2.51cto.com/wyfs02/M02/8F/80/wKiom1jh9iny_6n-AABHE0hhC3Y511.jpg" target="_blank"></a>

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

<a href="https://s2.51cto.com/wyfs02/M02/8F/7E/wKioL1jh9inwPy1BAABGqcPAdCI656.jpg" target="_blank"></a>

例如3:

參考底下這個範例:

<a href="https://s2.51cto.com/wyfs02/M00/8F/80/wKiom1jh9imgvQV5AABmeRatrks991.jpg" target="_blank"></a>

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

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

<a href="https://s3.51cto.com/wyfs02/M02/8F/7E/wKioL1jh9iqiMLDkAABS3cvNXBs015.jpg" target="_blank"></a>

五、awk指令:

awk也是一個資料處理工具,最基本功能是在檔案或字元串中基于指定規則來分解抽取資訊,也可以基于指定的規則來輸出資料。其實他更像一門程式設計語言,他可以自定義變量,有條件語句,有循環,有數組,有正則,有函數等。

1、awk和sed的差別:

sed側重于對行的處理,常常作用于一整個行的處理;

awk則比較傾向于一行當中分成數個字段來處理。

2、awk的三種調用方式:

①指令行方式(是最常用的方式)

格式:

<a href="https://s3.51cto.com/wyfs02/M00/8F/80/wKiom1jh9iriPDo-AACJ8KrGCas784.jpg" target="_blank"></a>

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

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

例如:

<a href="https://s3.51cto.com/wyfs02/M00/8F/7E/wKioL1jh9irwLgboAACT14vNML4637.jpg" target="_blank"></a>

腳本執行結果如下:

<a href="https://s1.51cto.com/wyfs02/M01/8F/81/wKiom1jh9ivxuaDuAABRh1ZP2EY975.jpg" target="_blank"></a>

執行的指令’是真正awk指令, 輸入檔案 是待處理的檔案。

輸入檔案可以是多于一個檔案的檔案清單,awk将按順序處理清單中的每個檔案。

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

②shell腳本方式

說明:将所有的awk指令插入一個檔案,并使awk程式可執行,然後awk指令解釋器作為腳本的首行,以便通過鍵入腳本名稱來調用。

相當于shell腳本首行的:#!/bin/sh可以換成:#!/bin/awk

③将所有的awk指令插入一個單獨檔案,然後調用

awk    -f     awk腳本檔案     輸入檔案

說明:用-f加載awk腳本檔案中的腳本

3、awk的模式和動作

說明:任何awk語句都由模式和動作組成(awk_pattern { actions }),模式就是條件(可省略),在一個awk腳本中可能有許多語句。

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

模式可以是任何條件語句或正規表達式等。

模式可以是以下幾種類型:

<a href="https://s1.51cto.com/wyfs02/M00/8F/7E/wKioL1jh9iuh5O8nAAGpsf1iNkk431.jpg" target="_blank"></a>

<a href="https://s1.51cto.com/wyfs02/M01/8F/7E/wKioL1jh9iyTc97NAAFN1KXLkpc076.jpg" target="_blank"></a>

布爾表達式用作模式,當條件成立時,觸發相應的動作執行。

布爾表達式中可以使用變量(如字段變量$1,$2等)和正規表達式。

&amp;&amp;(與) 和 ||(或) 可以連接配接兩個正規表達式或者布爾表達式,構成混合表達式,!(非) 可以用于布爾表達式或者正規表達式之前。

實際動作在大括号{ }内指明。動作大多數用來列印,但是還有些更長的代碼諸如i f和循環語句及循環退出結構。如果不指明采取動作,awk将列印出所有浏覽出來的記錄。

awk執行時,其浏覽域标記為$1,$2...$n。這種方法稱為域辨別。使用這些域辨別将更容易對域進行進一步處理。

使用$1 ,$3表示參照第1和第3域,注意這裡用逗号做域分隔。如果希望列印一個有5個域的記錄的所有域,不必指明$1 , $2 , $3 , $4 , $5,可使用$0,意即所有域。

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

注意:

模式包括兩個特殊字段 BEGIN和END。

使用BEGIN語句設定計數和列印頭。BEGIN語句使用在任何文本浏覽動作之前,之後文本浏覽動作依據輸入文本開始執行。

END語句用來在awk完成文本浏覽動作後列印輸出文本總數和結尾狀态标志。

awk的運作過程:

<a href="https://s1.51cto.com/wyfs02/M01/8F/81/wKiom1jh9i3wM4vZAAQ3EVz0jIQ501.jpg" target="_blank"></a>

入門執行個體:

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

<a href="https://s2.51cto.com/wyfs02/M02/8F/81/wKiom1jh9i2hmWy6AABsGGvf_lg551.jpg" target="_blank"></a>

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

<a href="https://s2.51cto.com/wyfs02/M02/8F/7E/wKioL1jh9i6CTO4XAABc0DcLLuY566.jpg" target="_blank"></a>

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

<a href="https://s4.51cto.com/wyfs02/M00/8F/81/wKiom1jh9i6gKV_AAABk0tn6DcM632.jpg" target="_blank"></a>

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

<a href="https://s4.51cto.com/wyfs02/M00/8F/7E/wKioL1jh9i7SyosFAAE5LoucyQ0122.jpg" target="_blank"></a>

例3:如果隻是顯示/etc/passwd檔案中的UID大于500的使用者名和登入shell,而賬戶與shell之間以逗号分割,而且在所有行添加列名name,shell,在最後一行添加"blue,/bin/nosh"。

<a href="https://s4.51cto.com/wyfs02/M01/8F/81/wKiom1jh9i-DXc4SAADVd73cmCE191.jpg" target="_blank"></a>

注:

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

2.awk工作流程是這樣的:先執行BEGING,然後讀取檔案,讀入有\n換行符分割的一條記錄,然後将記錄按指定的域分隔符劃分域,填充域,$0則表示所有域,$1表示第一個域,$n表示第n個域,随後開始執行模式所對應的動作。接着開始讀入第二條記錄······直到所有的記錄都讀完,最後執行END操作。

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

<a href="https://s4.51cto.com/wyfs02/M01/8F/7E/wKioL1jh9i_w0wDTAAD9ZFw_bRM080.jpg" target="_blank"></a>

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

<a href="https://s4.51cto.com/wyfs02/M02/8F/81/wKiom1jh9i-BtIaqAADD9Gxe1uM418.jpg" target="_blank"></a>

說明:這種是pattern(模式)的使用示例,比對了pattern(這裡是root)的行才會執行action(沒有指定action,預設輸出每行的内容)。

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

<a href="https://s4.51cto.com/wyfs02/M01/8F/7E/wKioL1jh9jDg9tncAACE_WR0d5c682.jpg" target="_blank"></a>

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

<a href="https://s5.51cto.com/wyfs02/M02/8F/81/wKiom1jh9jCC4RicAABVUO15Ugg930.jpg" target="_blank"></a>

說明:這裡指定了動作是{print $7}

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

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

<a href="https://s4.51cto.com/wyfs02/M02/8F/7E/wKioL1jh9jDDAoq2AACfKLjC0Cs185.jpg" target="_blank"></a>

使用awk指令抽取使用者名和IP區域的資料:

<a href="https://s4.51cto.com/wyfs02/M02/8F/7E/wKioL1jh9jCwE19UAABfLKaaZuQ062.jpg" target="_blank"></a>

<a href="https://s5.51cto.com/wyfs02/M00/8F/81/wKiom1jh9jHxX1L4AAB8zk6ZEHo186.jpg" target="_blank"></a>

4、awk内置變量

說明:awk有許多内置變量用來設定環境資訊,下面給出了最常用的一些變量:

<a href="https://s5.51cto.com/wyfs02/M00/8F/81/wKiom1jh9jGz-KsTAAH7awsCw6s512.jpg" target="_blank"></a>

例1:統計/etc/passwd:檔案名,每行的行号,每行的列數,對應的完整行内容:

<a href="https://s2.51cto.com/wyfs02/M01/8F/81/wKiom1jh9l3ACfmlAAHt_l7mr5Q114.jpg" target="_blank"></a>

顯示所有賬戶的記錄,并帶有其記錄号,并在END部分列印輸入檔案名:

<a href="https://s2.51cto.com/wyfs02/M00/8F/7E/wKioL1jh9l2TPtyaAABvTyqaVKU668.jpg" target="_blank"></a>

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

<a href="https://s3.51cto.com/wyfs02/M01/8F/7E/wKioL1jh9l3wrJBYAABNVwZSez8601.jpg" target="_blank"></a>

<a href="https://s3.51cto.com/wyfs02/M01/8F/81/wKiom1jh9l6w8HNjAAAVzjIU6Iw416.jpg" target="_blank"></a>

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

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

<a href="https://s3.51cto.com/wyfs02/M01/8F/7E/wKioL1jh9l7h-oLBAACcVzqcLVI607.jpg" target="_blank"></a>

<a href="https://s1.51cto.com/wyfs02/M02/8F/81/wKiom1jh9l6ChVrdAAAxJnq722k217.jpg" target="_blank"></a>

例3:統計某個檔案夾下的檔案占用的位元組數

<a href="https://s3.51cto.com/wyfs02/M02/8F/7E/wKioL1jh9l6jtgdzAABAXiXUCgY794.jpg" target="_blank"></a>

如果以M為機關顯示:

<a href="https://s1.51cto.com/wyfs02/M02/8F/81/wKiom1jh9l-wjBPJAAA9bHIbtsI449.jpg" target="_blank"></a>

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

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

<a href="https://s1.51cto.com/wyfs02/M00/8F/81/wKiom1jh9l-x8bNmAACFcE7_rm0025.jpg" target="_blank"></a>

六、函數及腳本的綜合應用

1.  shell允許将一組指令集或語句形成一個可用塊,這些塊稱為shell函數

2.  函數由兩部分組成:函數标題(函數名)、函數體(指令集合)

标題是函數名。函數體是函數内的指令集合。

标題名應該唯一;如果不是,将會混淆結果,因為腳本在檢視調用腳本前将首先搜尋函數調用相應的shell。

定義函數的格式

   第一種

函數名()

{

指令

}

   第二種

Function 函數名()

4、舉例

例1:删除檔案中的空行

這個腳本(腳本名為del.lines)可以處理一個或多個檔案。每個檔案在用sed删除空行之前要先核實是否存在。

sed的輸出被導入一個檔案名中含有$$的臨時檔案,最後這個臨時檔案又被移回到原來的檔案中。

該腳本使用shift指令取得所有的檔案名,用while循環逐個處理所有的檔案,直至處理完

為止。可以使用del.lines --help獲得一個簡短的幫助 。

<a href="https://s1.51cto.com/wyfs02/M02/8F/7E/wKioL1jh9mCBq1KiAAJ0WMUgVWM433.jpg" target="_blank"></a>

儲存後給腳本檔案增加執行權限:chmod  +x  del.lines

執行腳本進行測試:

<a href="https://s3.51cto.com/wyfs02/M00/8F/7E/wKioL1jh9mCTuGtjAAA7HDgy8oY297.jpg" target="_blank"></a>

1、basename指令能夠從路徑中分離出檔案名。通常用于shell腳本中

2、shift語句用于遷移位置變量,将$1~$9 依次向左傳遞

例如,若目前腳本程式獲得的位置變量如下:

$1=file1、$2=file2、$3=file3、$4=file4

則執行一次shift指令後,各位置變量為:

$1=file2、$2=file3、$3=file4

再次執行shift指令後,各位置變量為:

$1=file3、$2=file4

例2:如果某些日志檔案超過了特定的長度(如8K),那麼它的内容将被倒換到另一個檔案中,并清除原有檔案中的内容.

系統中的有些日志檔案增長十分迅速,每天手工檢查這些日志檔案的長度并倒換這些日志檔案(通常是給檔案名加個時間戳)是非常乏味的。可以編寫一個腳本來自動完成這項工作。該腳本将送出給cron程序來運作,如果某個日志檔案超過了特定的長度,那麼它的内容将被倒換到另一個檔案中,并清除原有檔案中的内容。

該腳本中日志檔案的長度限制是由變量BLOCK_LIMIT設定的。這一數字代表了塊數目,在本例中是8(塊大小預設為4K)。可以按照自己的需求把這一數字設得更高。所有要檢查的日志檔案名都儲存在變量LOGS中。

這裡使用了一個for循環來依次檢查每一個日志檔案,使用du指令來擷取日志檔案長度。

如果相應的檔案長度大于BLOCK_LIMIT變量所規定的值,那麼該檔案将被拷貝到一個檔案

名含有時間戳的檔案中,原先的檔案長度将被截斷為0。

<a href="https://s4.51cto.com/wyfs02/M01/8F/81/wKiom1jh9mChdzBgAAHRsiWrNro825.jpg" target="_blank"></a>

注:du 并不是顯示檔案的實際大小,而是顯示檔案所占用的 block 大小,預設linux系統分區的 block size 是4k,也就是說即使檔案隻有1個位元組,也會占用4k.

ls-l則是檔案的實際大小。

總結:

   Shift:用于向左遷移位置變量,比如同時對多個檔案進行操作,使用$1取第一個檔案,當第一個檔案操作完後執行shift指令将第一個檔案左移,然後第二個檔案補位,此時$1就代表第二個檔案,然後對第二個檔案進行操作,依次類推

   Continue:用于結束當次循環,取下一個變量進行新的循環

   Basename:傳回路徑中的檔案名部分

   Exit NUM:num=0時,正常退出循環,num=1-255時錯誤退出循環