awk詳解

AWK

簡介

AWK是一種優良的文本處理工具。它不只是 Linux 中也是任何環境中現有的功能最強大的數據處理引擎之一。這種編程及數據操做語言(其名稱得自於它的創始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首個字母)的最大功能取決於一我的所擁有的知識。AWK 提供了極其強大的功能:能夠進行樣式裝入、流控制、數學運算符、進程控制語句甚至於內置的變量和函數。它具有了一個完整的語言所應具備的幾乎全部精美特性。實際上 AWK 的確擁有本身的語言:AWK 程序設計語言, 三位建立者已將它正式定義爲「樣式掃描和處理語言」。它容許您建立簡短的程序,這些程序讀取輸入文件、爲數據排序、處理數據、對輸入執行計算以及生成報表,還有無數其餘的功能。linux

使用方法

awk '{pattern + action}' {filenames}正則表達式

儘管操做可能會很複雜,但語法老是這樣,其中 pattern 表示 AWK 在數據中查找的內容,而 action 是在找到匹配內容時所執行的一系列命令。花括號({})不須要在程序中始終出現,但它們用於根據特定的模式對一系列指令進行分組。 pattern就是要表示的正則表達式,用斜槓括起來。awk語言的最基本功能是在文件或者字符串中基於指定規則瀏覽和抽取信息,awk抽取信息後,才能進行其餘文本操做。完整的awk腳本一般用來格式化文本文件中的信息。一般,awk是以文件的一行爲處理單位的。awk每接收文件的一行,而後執行相應的命令,來處理文本。shell

調用awk

  • 命令行方式

awk [-F field-separator] 'commands' input-file(s)
其中,commands 是真正awk命令,[-F域分隔符]是可選的。 input-file(s) 是待處理的文件。
在awk中,文件的每一行中,由域分隔符分開的每一項稱爲一個域。一般,在不指名-F域分隔符的狀況下,默認的域分隔符是空格。express

  • shell腳本方式

將全部的awk命令插入一個文件,並使awk程序可執行,而後awk命令解釋器做爲腳本的首行,一遍經過鍵入腳本名稱來調用。
至關於shell腳本首行的:#!/bin/sh
能夠換成:#!/bin/awk編程

  • 將全部的awk命令插入一個單獨文件,而後調用:

awk -f awk-script-file input-file(s)
其中,-f選項加載awk-script-file中的awk腳本,input-file(s)跟上面的是同樣的。數組

入門實例(取出linux最近登陸的五個用戶的用戶名)bash

# 下面是取出最近登陸的五個用戶的信息

[root@localhost ~]# last -n 5
root     pts/1   192.168.1.100  Tue Feb 10 11:21   still logged in
test     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    120.239.75.53  Fri Sep  5 14:09 - 14:10  (00:01)

# 若是隻是顯示最近登陸的5個賬號的用戶名

$ last -n 5 | awk  '{print $1}'
root
test
root
dmtsai
root

# awk工做流程是這樣的:讀入有'\n'換行符分割的一條記錄,而後將記錄按指定的域分隔符劃分域,填充域,$0則表示全部域,$1表示第一個域,$n表示第n個域。默認域分隔符是"空白鍵" 或 "[tab]鍵",因此$1表示登陸用戶,$3表示登陸用戶ip,以此類推。

入門實例(只顯示/etc/passwd的帳戶)函數

$ cat /etc/passwd | awk  -F ':' '{print $1}'  
root
daemon
bin
sys

# 這種是awk+action的示例,每行都會執行action{print $1}。

# -F指定域分隔符爲':'。

# 若是隻是顯示/etc/passwd的帳戶和帳戶對應的shell,而帳戶與shell之間以tab鍵分割

$ cat /etc/passwd | awk  -F ':' '{print $1"\t"$7}'
root    /bin/bash
daemon  /bin/sh
bin     /bin/sh
sys     /bin/sh
 

# 若是隻是顯示/etc/passwd的帳戶和帳戶對應的shell,而帳戶與shell之間以逗號分割,並且在全部行添加列名name,shell,在最後一行添加"blue,/bin/nosh"。

$ cat /etc/passwd |awk  -F ':' 'BEGIN {print "name,shell"}  {print $1","$7} END {print "blue,/bin/nosh"}'
name,shell
root,/bin/bash
daemon,/bin/sh
bin,/bin/sh
sys,/bin/sh
....
blue,/bin/nosh

# awk工做流程是這樣的:先執行BEGING,而後讀取文件,讀入有/n換行符分割的一條記錄,而後將記錄按指定的域分隔符劃分域,填充域,$0則表示全部域,$1表示第一個域,$n表示第n個域,隨後開始執行模式所對應的動做action。接着開始讀入第二條記錄······直到全部的記錄都讀完,最後執行END操做。


# 搜索/etc/passwd有root關鍵字的全部行

$ awk -F: '/root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash

# 這種是pattern的使用示例,匹配了pattern(這裏是root)的行纔會執行action(沒有指定action,默認輸出每行的內容)。

# 搜索支持正則,例如找root開頭的: awk -F: '/^root/' /etc/passwd

# 搜索/etc/passwd有root關鍵字的全部行,並顯示對應的shell

$ awk -F: '/root/{print $7}' /etc/passwd        
/bin/bash

# 這裏指定了action{print $7}

awk 內置變量

awk有許多內置變量用來設置環境信息,這些變量能夠被改變,下面給出了最經常使用的一些變量。工具

$n                 # 當前記錄的第n個字段,好比n爲1表示第一個字段,n爲2表示第二個字段。

$0                 # 這個變量包含執行過程當中當前行的文本內容。

ARGC             # 命令行參數的數目。

ARGIND             # 命令行中當前文件的位置(從0開始算)。

ARGV             # 包含命令行參數的數組。

CONVFMT         # 數字轉換格式(默認值爲%.6g)。

ENVIRON         # 環境變量關聯數組。

ERRNO             # 最後一個系統錯誤的描述。

FIELDWIDTHS     # 字段寬度列表(用空格鍵分隔)。

FILENAME         # 當前輸入文件的名。

NR                 # 表示記錄數,在執行過程當中對應於當前的行號

FNR             # 同NR,但相對於當前文件。

FS                 # 字段分隔符(默認是任何空格)。

IGNORECASE         # 若是爲真,則進行忽略大小寫的匹配。

NF                 # 表示字段數,在執行過程當中對應於當前的字段數。 print $NF答應一行中最後一個字段

OFMT             # 數字的輸出格式(默認值是%.6g)。

OFS             # 輸出字段分隔符(默認值是一個空格)。

ORS             # 輸出記錄分隔符(默認值是一個換行符)。

RS                 # 記錄分隔符(默認是一個換行符)。

RSTART             # 由match函數所匹配的字符串的第一個位置。

RLENGTH         # 由match函數所匹配的字符串的長度。

SUBSEP             # 數組下標分隔符(默認值是34)。

此外,$0變量是指整條記錄。$1表示當前行的第一個域,$2表示當前行的第二個域,......以此類推。命令行

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

$ awk  -F ':'  '{print "filename:" FILENAME ",linenumber:" NR ",columns:" NF ",linecontent:"$0}' /etc/passwd
filename:/etc/passwd,linenumber:1,columns:7,linecontent:root:x:0:0:root:/root:/bin/bash
filename:/etc/passwd,linenumber:2,columns:7,linecontent:daemon:x:1:1:daemon:/usr/sbin:/bin/sh
filename:/etc/passwd,linenumber:3,columns:7,linecontent:bin:x:2:2:bin:/bin:/bin/sh
filename:/etc/passwd,linenumber:4,columns:7,linecontent:sys:x:3:3:sys:/dev:/bin/sh

使用printf替代print,可讓代碼更加簡潔,易讀

awk -F ':' '{printf("filename:%s,linenumber:%s,columns:%s,linecontent:%s\n",FILENAME,NR,NF,$0)}' /etc/passwd

print 和 printf

awk中同時提供了print和printf兩種打印輸出的函數。其中print函數的參數能夠是變量、數值或者字符串。字符串必須用雙引號引用,參數用逗號分隔。若是沒有逗號,參數就串聯在一塊兒而沒法區分。這裏,逗號的做用與輸出文件的分隔符的做用是同樣的,只是後者是空格而已。printf函數,其用法和c語言中printf基本類似,能夠格式化字符串,輸出複雜時,printf更加好用,代碼更易懂。

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

awk編程

變量和賦值

除了awk的內置變量,awk還能夠自定義變量。

下面統計/etc/passwd的帳戶人數

awk '{count++;print $0;} END{print "user count is ", count}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
......
user count is  40

count是自定義變量。以前的action{}裏都是隻有一個print,其實print只是一個語句,而action{}能夠有多個語句,以;號隔開。

這裏沒有初始化count,雖然默認是0,可是穩當的作法仍是初始化爲0:

awk 'BEGIN {count=0;print "[start]user count is ", count} {count=count+1;print $0;} END{print "[end]user count is ", count}' /etc/passwd
[start]user count is  0
root:x:0:0:root:/root:/bin/bash
...
[end]user count is  40

統計某個文件夾下的文件佔用的字節數

ls -l |awk 'BEGIN {size=0;} {size=size+$5;} END{print "[end]size is ", size}'
[end]size is  8657198

若是以M爲單位顯示:

ls -l |awk 'BEGIN {size=0;} {size=size+$5;} END{print "[end]size is ", size/1024/1024,"M"}' 
[end]size is  8.25889 M

注意,統計不包括文件夾的子目錄。

條件語句

awk中的條件語句是從C語言中借鑑來的,見以下聲明方式:

if (expression) {
    statement;
    statement;
    ... ...
}

if (expression) {
    statement;
} else {
    statement2;
}

if (expression) {
    statement1;
} else if (expression1) {
    statement2;
} else {
    statement3;
}

統計某個文件夾下的文件佔用的字節數,過濾4096大小的文件(通常都是文件夾):

ls -l |awk 'BEGIN {size=0;print "[start]size is ", size} {if($5!=4096){size=size+$5;}} END{print "[end]size is ", size/1024/1024,"M"}' 
[end]size is  8.22339 M

循環語句

awk中的循環語句一樣借鑑於C語言,支持while、do/while、for、break、continue,這些關鍵字的語義和C語言中的語義徹底相同。

# for循環

for(變量 in 數組)  
{語句} 
 
for(變量;條件;表達式) 
{語句} 


# while循環

while(表達式) 
    {語句} 


# do...while循環

do  
{語句} while(條件) 


# 其餘相關語句

break:退出程序循環

continue: 進入下一次循環

next:讀取下一個輸入行

exit:退出主輸入循環,進入END,若沒有END或END中有exit語句,則退出腳本。

數組

由於awk中數組的下標能夠是數字和字母,數組的下標一般被稱爲關鍵字(key)。值和關鍵字都存儲在內部的一張針對key/value應用hash的表格裏。因爲hash不是順序存儲,所以在顯示數組內容時會發現,它們並非按照你預料的順序顯示出來的。數組和變量同樣,都是在使用時自動建立的,awk也一樣會自動判斷其存儲的是數字仍是字符串。通常而言,awk中的數組用來從記錄中收集信息,能夠用於計算總和、統計單詞以及跟蹤模板被匹配的次數等等。

顯示/etc/passwd的帳戶

$ awk -F ':' 'BEGIN {count=0;} {name[count] = $1;count++;}; END{for (i = 0; i < NR; i++) print i, name[i]}' /etc/passwd
0 root
1 daemon
2 bin
3 sys
4 sync
5 games
......

awk運算

算術運算:(+,-,*,/,&,!,……,++,--)

全部用做算術運算符進行操做時,操做數自動轉爲數值,全部非數值都變爲0

賦值運算:(=, +=, -=,*=,/=,%=,……=,**=)

邏輯運算符: (||, &&)

關係運算符:(<, <=, >,>=,!=, ==)

正則運算符:(~,~!)(匹配正則表達式,與不匹配正則表達式)

$ awk 'BEGIN{a="100testa";if(a ~ /^100*/){print "ok";}}'
ok

時間函數

格式 描述
mktime( YYYY MM dd HH MM ss[ DST]) 生成時間格式
strftime([format [, timestamp]]) 格式化時間輸出,將時間戳轉爲時間字符串 具體格式,見下表.
systime() 獲得時間戳,返回從1970年1月1日開始到當前時間(不計閏年)的整秒數

strftime日期和時間格式說明符 :

格式 描述
%a 星期幾的縮寫(Sun)
%A 星期幾的完整寫法(Sunday)
%b 月名的縮寫(Oct)
%B 月名的完整寫法(October)
%c 本地日期和時間
%d 十進制日期
%D 日期 08/20/99
%e 日期,若是隻有一位會補上一個空格
%H 用十進制表示24小時格式的小時
%I 用十進制表示12小時格式的小時
%j 從1月1日起一年中的第幾天
%m 十進制表示的月份
%M 十進制表示的分鐘
%p 12小時表示法(AM/PM)
%S 十進制表示的秒
%U 十進制表示的一年中的第幾個星期(星期天做爲一個星期的開始)
%w 十進制表示的星期幾(星期天是0)
%W 十進制表示的一年中的第幾個星期(星期一做爲一個星期的開始)
%x 從新設置本地日期(08/20/99)
%X 從新設置本地時間(12:00:00)
%y 兩位數字表示的年(99)
%Y 當前月份
%Z 時區(PDT)
%% 百分號(%)
相關文章
相關標籤/搜索