awk是linux上非常好用的文本處理工具,常用於指定列的處理,包括獲取指定列的內容、根據指定列匹配關系輸出等文本處理。本文主要描述awk命令的基本語法、正則表達式與操作符的使用、常用內置變量的含義和使用方法、內置字符串函數的使用方法。
awk基本語法
awk [ -F 分隔符] [ -v 變量名=值 ] 'BEGING{語句} 條件類型1{動作1} 條件類型2{動作2}... END{語句}' 輸入的文件
命令格式說明:
(1)awk命令格式由四部分組成。選項、BEGIN、END和帶條件類型和動作的語句。這四個部分都是可選項,可省略任意部分。
(2)-F表示設置列分隔符,默認為空格。
(3)-v 表示初始化一個變量或者用於向awk命令傳入外部變量值,shell編程中常用。
(4)條件類型可以是正則表達式、條件語句、復合語句以及行匹配范圍等內容。條件類型為可選設置。如果設置條件,只處理匹配條件的行執行動作。如果未設置,awk命令則認為所有行都是匹配的,並執行動作語句。動作表示執行的命令,命令必須放在大括號{}內。
(5)必須了解這些符號。$0表示行,$1、$2、$3...$n分別表示第1列、第2列、第3列...第n列。awk命令經常會使用這些符號去做匹配、打印指定指定列等操作。
awk命令處理流程:
(1)執行BEGIN{} 語句塊中的內容。BEGIN語句通常用戶變量初始化、打印輸出表格的表頭。
(2)從文件或者stdin中讀取一行。然后根據條件類型的匹配關系,判斷是否需要執行后面的動作。直到做完所有的動作和條件類型。重復這個過程,直到文件所有行處理完成。
(3)執行END語句塊中的內容。END語句塊常用於分析匯總等統計信息,比如統計文件行數。
基本使用實例
下面我們通過一些基本的實例來直觀了解下awk命令的各選項和條件類型、動作的基本用法,這些實例也是awk操作或者shell編程中最常見的幾種用法。如下
(1)$0、$1、$2、$3...$n內容
echo "2017 12 20" | awk '{print "$0="$0,"$1="$1,"$2="$2,"$3="$3}' #輸出$0=2017 12 20 $1=2017 $2=12 $3=20
從結果輸出可以知道,$0表示整行內容,$1、$2表示執行列。print中分割字段的逗號","默認輸出為空格。如果需要輸出以逗號分隔可以用如下方式:
echo "2017 12 20" | awk '{print "$0="$0 "," "$1="$1 "," "$2="$2 "," "$3="$3}' #輸出$0=2017 12 20,$1=2017,$2=12,$3=20
(2)利用-F選項指定分隔符獲取匹配行的指定列。
echo "2017-12-20" | awk -F"-" '{print $1,$2,$3}' #獲取第1、2、3列內容,輸出2017 12 20
如果需要考慮多個分隔符的行處理情況呢,可以通過-F '[分隔符1 分隔符2]'設置。如下一行同時包含破折號"-"、反斜干分隔符"/",獲取指定第1、2、3列內容。命令如下:
echo "2017-12/20" | awk -F"[-/]" '{print $1,$2,$3}' #輸出2017 12 20
(3)向awk命令傳入外部變量,常用於shell編程中。
var1=5 awk -v var=${var1} 'BEGIN{for(i=0;i<=var;i++)print i}' #輸出0 1 2 3 4 5
(4)BEGIN使用方法
awk 'BEGIN{num=5;for(i=0;i<=num;i++)print i}'
awk 'BEGIN{print "Begin deal with files"}' #處理文件前打印提示信息
(5)使用END語句統計文件行數。舉例如下:
awk 'END{print NR}' /etc/passwd
說明:NR表示文件已讀取的行數,END語句塊是在文本所有行處理后執行,所以打印NR數值就是文件行數。
awk中正則表達式與條件操作符
awk中正則表達式匹配操作中經常用到字符如下:
. * + ? $ | \ [] {} ()
條件操作符如下:
<(小於) <=(小於等於) ==(等於) >(大於) >=(大於等於) !=(不等於) ~(匹配正則表達式) !~(不匹配正則表達式)
其中<、>、<=等操作符用法比較簡單,這里主要講~(匹配正則表達式)、 !~(不匹配正則表達式)兩個表達式的用法。
基本實例如下:
(1)打印第1個字段包含root字符串的行
awk -F":" '{if($1~/root/)print $0}' /etc/passwd #寫法一 awk -F":" '$1~/root/{print $0}' /etc/passwd #寫法二
(2)打印第1個字段不包含root字符串的行
awk -F":" '{if($1 !~ /root/)print $0}' /etc/passwd #寫法一 awk -F":" '$1 !~ /root/{print $0}' /etc/passwd #寫法二
(3)打印第1個字段等於root字符串的行
awk -F":" '{if($1 == "root")print $0}' /etc/passwd #寫法一 awk -F":" '$1 == "root"{print $0}' /etc/passwd #寫法二
(4)打印第1個字段不等於root字符串的行
awk -F":" '{if($1 != "root")print $0}' /etc/passwd #寫法一 awk -F":" '$1 != "root"{print $0}' /etc/passwd #寫法二
(5)打印用戶ID小於500的用戶
awk -F":" '{if($3<500)print $0}' /etc/passwd
(6)打印行首為oracle的行
awk -F":" '{if($1~/^oracle/)print $0}' /etc/passwd
(7)打印匹配oracle或者root字符串的行
awk -F":" '{if($1~/(root|oracle)/)print $0}' /etc/passwd #用正則表達式元字符|的方式 awk -F":" '{if($1~/root/ || $1~/oracle/)print $0}' /etc/passwd #用或||的方式
說明:豎線符"|"表示匹配豎線"|"兩邊模式之一。使用豎線符時,語句必須用圓括號()括起來。
(8)打印同時匹配oracle和root的行
awk -F":" '{if($1=="root" && $3=="0")print $0}' /etc/passwd
awk內置變量
awk的內置變量包括FS、NF、OFS、ORS、NR等內容,下面逐一列舉其含義和用法。
(1)FS 表示用於設置列的分隔符,與-F選項功能相同。缺省情況下為空格。舉例如下:
echo "2017-12-20" |awk 'BEGIN{FS="-"}{print $1,$2,$3}' #輸出2017 12 20
(2)NF 表示一行記錄列的總數。如果需要打印最后一列內容,舉例如下:
echo "/usr/local/bin/python" | awk -F '/' '{print $NF}' #輸出python
說明:NF常用於打印倒數指定列的內容。
如打印指定列到最后一列的內容,方法如下:
awk -F " " '{for (i=4;i<=NF;i++)printf("%s ", $i);print ""}' file.txt
(3)OFS 表示指定輸出字段分隔符,缺省為空格。舉例如下:
echo "1990 09 09" | awk 'BEGIN{OFS="-"}{print $1,$2,$3}' #輸出1990-09-09
(4)ORS 表示輸出行記錄的分隔符,默認為換行符(\n)。如果需要設置輸出行的分隔符為#,可以如下表示:
echo -e "1990\n09\n09" | awk 'BEGIN{ORS="#"}{print $0}' #輸出1990#09#09#
(5)NR 表示已讀的記錄數。如果需要打印文件行數,舉例如下:
awk 'END{print NR}' /etc/passwd
(6)FILENAME 表示當前處理文件名。舉例如下:
awk 'END{print FILENAME}' /etc/passwd
awk內置字符串函數
(1)length(string) 返回計算字符串string的長度。舉例如下:
echo "Hello World" | awk '{print length($0)}' #輸出11
(2)index(string,substr) 返回待查找字符substr在字符串string中的位置,其中substr必須用雙引號將字符串括起來。舉例如下:
echo "Hello World" | awk '{print index($0,"o")}' #輸出5 awk 'BEGIN{print index("Hello World","o")}' #輸出5
(3)match(string,regex) 檢查正則表達式regex是否能夠匹配字符串,如果匹配返回值為非0,如果未匹配,返回0。舉例如下:
awk 'BEGIN{print match("Hello World",'o')}' #查找字符串o第一次出現的位置,輸出1 echo "Hello World" | awk '{print match($0,'o')}' #同上,輸出1 awk 'BEGIN{print match("Hello World",/[Oo]/)}' #查找字符串大寫或小寫o第一次出現的位置。輸出5
(4)split(string,array,delimeter) 使用指定的分隔符delimeter分割字符串string,並將分割出的結果保存到arayr數組。split()函數返回值為數組長度。舉例如下:
echo "123#456#789" | awk '{len=split($0,arr,"#");for(i=1;i<=len;i++)print arr[i]}'
說明:通過獲取到的數組長度,通過循環方式獲取數組中的內容,其中數組下標是從1開始計算。更為簡便的獲取方法如下:
echo "123#456#789" | awk '{split($0,arr,"#");for(i in arr)print arr[i]}'
(5)sub(regex,string) 表示用字符串string替換正則表達式regex匹配的內容。舉例如下:
echo "Java:Python:Java:C" | awk 'sub(/Java/,"Ruby",$0)' #輸出Ruby:Python:Java:C
(6)substr(string,pos) 獲取字符串sting中從指定位置pos后的內容。舉例如下
echo "Java:Python:C" | awk '{print substr($0,6)}' #輸出Python:C
(7)substr(string,pos,n) 獲取字符串string中從指定位置pos開始長度為n的內容
echo "Java:Python:C" | awk '{print substr($0,1,4)}' #輸出Java
(8)gsub(regex,string) 表示使用字符串string替換正則表達式regex匹配的內容。舉例如下:
echo "Java:Python:Java:C" | awk 'gsub(/Java/,"Ruby")' #輸出Ruby:Python:Ruby:C
(9)gsub(regex,string,target) 表示在指定的范圍內,使用字符串string替換正則表達式regex匹配的內容。舉例如下:
echo "Learn Shell at 2013-08-08" | awk 'gsub(/-/,":",$4)' #輸出Learn Shell at 2013:08:08
awk內置算術函數
這里主要介紹int()、srand()、rand()3個算術函數。
(1)int(x) 返回x的整數
awk 'BEGIN{i=3.1415926;print int(i)}' #輸出3
(2)rand() 返回0~1的任意數字。
awk 'BEGIN{srand();num=rand();print num}' #輸出0~1的任意值,每執行一次變化一次。
說明:如果不加上srand()函數,每次執行打印的值都相同。
awk內容打印(printf&print)
awk可以使用print和printf輸出字符串。主要區別是printf可以自定義輸出的模式,輸出內容后不換行。print輸出內容后會自動換行。
printf使用格式:
(1)printf([格式控制符],參數)
(2) printf [格式控制符],參數
格式(1)和(2)的區別就是帶不帶小括號。個人覺得帶小括號更直觀。畢竟是個函數。下面這說明一下printf格式控制符中的常用格式和修飾符。
常用格式:%d表示整數、%s表示字符串。
修飾符:破折號"-"表示左對齊、Width表示步長。
printf基本使用實例
(1)格式化輸出字符串
$ echo -e "12345 678\n123456788 890" | awk '{printf("%-11d %-5d\n",$1,$2)}' $ echo -e "12345 678\n123456788 890" | awk '{printf"%-11d %-5d\n",$1,$2}' #不帶小括號
如果使用print函數的話,就可以自動換行了,不需要手工添加換行符。同樣,print也是可以帶小括號。
$ echo -e "12345 678\n123456788 890" | awk '{print $1,$2}'
(2)利用printf生成數據。使用方法如下
$ awk 'BEGIN{data_format="136%03d\n";for(i=0;i<=3;i++)printf(data_format,i)}'
小結
本文內容介紹了awk命令的基本語法和常用實例。awk具有強大的文本處理能力,掌握awk命令的基本內容可以完成工作上遇到的大部分問題。另外,awk構造大批量測試數據有非常高的效率。