awk命令使用詳解

介紹

AWK是一種處理文本文件的語言,是一個強大的文本分析工具,之因此叫AWK是由於其取了三位創始人 Alfred Aho,Peter Weinberger, 和 Brian Kernighan 的 Family Name 的首字符。java

語法
  • 第一種形式
$ awk 'BEGIN{}pattern{commands}END{}' file
複製代碼
  • 第二種形式
$ standard output | 'BEGIN{}pattern{commands}END{}'
複製代碼
工做原理

其中數字1,2,3…表明是文本中的數據行python

BEGIN{} 表示在處理文本數據以前進行一些操做正則表達式

pattern{commands} 表示從文本中的第一行開始匹配知足pattern規則的行,執行commands命令,直到文本最後一行spring

END{} 表示在處理文本數據以後進行一些操做shell

內建變量
內置變量 含義
$0 整行內容
1-n 當前行的第1-n個字段
NF 當前行的字段個數,也就是有多少列
NR 當前的行號,從1開始計數
FNR 各文件分別計數的行號
FS 字段分隔符(默認以空格或tab鍵分割)
RS 輸入行分隔符。默認回車換行
OFS 輸出字段分隔符。默認爲空格
ORS 輸出行分隔符。默認爲回車換行
FILENAME 當前文件名

內置變量如何使用,咱們以文本score.txt內容來作演示vim

$ cat  score.txt
marry 90  49  23  14
join  44  55  66  24
smile 55  78  80  34
jack  20  51  66  44
複製代碼

使用$0來打印輸出文件的每一整行的內容數組

$ awk '{print $0}' score.txt
marry 90  49  23  14
join  44  55  66  24
smile 55  78  80  34
jack  20  51  66  44
複製代碼

注意:行匹配語句 awk ' ' 只能用單引號bash

使用$1$3來打印輸出文件的的每一行第1列和第3列內容ssh

$ awk '{print $1,$3}' score.txt
marry 49
join 55
smile 78
jack 51
複製代碼

使用NF來輸出每一行的列數tcp

$ awk  '{print NF}' score.txt
5
5
5
5
複製代碼

使用awk沒有指定分隔符,默認是以空格或者tab鍵來做分隔,在score.txt 文件中,通過分隔,每行都有5列

使用變量$NF來輸出文件

$ awk '{print $NF}' score.txt
14
24
34
44
複製代碼

從輸出結果咱們總結出,NF就表示每一行的最後一列,由於文件中每一行有5列,則NF = $5

以前咱們打印每一行的第1列和第3列咱們使用的是:$1,3;那麼如今咱們也可使用:**(NF-2)$(NF-4)**

$ awk '{print $(NF-4),$(NF-2)}' score.txt
marry 49
join 55
smile 78
jack 51
複製代碼

使用NR來輸出每一行的行號,此次咱們把每一行的內容也打印出來

$ awk '{print NR "\t" $0}' score.txt
1	marry 90  49  23  85
2	join  44  55  66  22
3	smile 55  78  80  24
4	jack  20  51  66  89
複製代碼

使用ORS來指定輸出每一行的指定的分隔符

$ awk 'BEGIN{ORS="---"} {print $1,$NF}' score.txt
marry 14---join 24---smile 34---jack 44---
複製代碼

指定了每一行的分隔符爲"---",如今輸出的每一行都用---作分隔,而不在是默認的回車換行作分隔

使用ORS指定了行的分隔符爲"---",可是如今咱們看到每一行輸出的分隔符仍是默認的空格來作分隔,好比:輸出第一行的 marry 14,如今咱們使用OFS來指定輸出字段的分隔符,好比:*

$ awk 'BEGIN{ORS="---";OFS="*"} {print $1,$NF}' score.txt
marry*14---join*24---smile*34---jack*44---
複製代碼

使用FS指定每一行的字段分隔符

$ awk 'BEGIN{FS=":"} {print $1,$NF}' /etc/passwd
root /bin/bash
bin /sbin/nologin
複製代碼

也可使用這種形式指定分隔符(-F的意思就是指定分隔符)

$ awk -F: '{print $1,$NF}'  /etc/passwd
複製代碼

若是指定多個分隔符,使用中括號[]包起來,裏面指定具體的分隔符

$ awk -F '[-:]'
複製代碼

使用FILENAME在處理多文件時候,能夠打印出當前的文件名

$ awk 'BEGIN{FS="[ :]"} {print FILENAME "\t" $1,$NF}' score.txt  /etc/passwd
score.txt	marry 14
score.txt	join 24
score.txt	smile 34
score.txt	jack 44
/etc/passwd	root /bin/bash
/etc/passwd	bin /sbin/nologin
複製代碼
使用重定向拆分文件

準備文件 netstat.txt

$ cat netstat.txt
Proto Recv-Q Send-Q Local-Address           Foreign-Address         State
tcp        0      0 0.0.0.0:111             0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN
tcp        0      0 192.168.10.10:22        192.168.10.1:65016      ESTABLISHED
tcp        0      0 192.168.10.10:22        192.168.10.1:57253      ESTABLISHED
tcp6       0      0 :::111                  :::*                    LISTEN
tcp6       0      0 :::22                   :::*                    LISTEN
tcp6       0      0 ::1:25                  :::*                    LISTEN
udp        0      0 0.0.0.0:1018            0.0.0.0:*               FIN_WAIT2
udp6       0      0 :::1018                 :::*                    FIN_WAIT2
udp6       0      0 :::111                  :::*                    ESTABLISHED
udp6       0      0 ::1:323                 :::*                    ESTABLISHED
複製代碼

以空格爲分隔符,按照$6(第6列)也就是State列進行拆分文件netstat.txt(其中NR!=1表示不處理表頭)

$ awk 'NR!=1{print > $6}' netstat.txt

$ ls
ESTABLISHED  FIN_WAIT2  LISTEN  netstat.txt

$ cat ESTABLISHED
tcp        0      0 192.168.10.10:22        192.168.10.1:65016      ESTABLISHED
tcp        0      0 192.168.10.10:22        192.168.10.1:57253      ESTABLISHED
udp6       0      0 :::111                  :::*                    ESTABLISHED
udp6       0      0 ::1:323                 :::*                    ESTABLISHED

$ cat FIN_WAIT2
udp        0      0 0.0.0.0:1018            0.0.0.0:*               FIN_WAIT2
udp6       0      0 :::1018                 :::*                    FIN_WAIT2

$ cat  LISTEN
tcp        0      0 0.0.0.0:111             0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN
tcp6       0      0 :::111                  :::*                    LISTEN
tcp6       0      0 :::22                   :::*                    LISTEN
tcp6       0      0 ::1:25                  :::*                    LISTEN
複製代碼

{print > $6} 是按照第6列進行拆分,將全部列輸出到文件中,咱們也能夠指定列輸出到文件中

$ awk 'NR!=1{print $1,$4> $6}' netstat.txt
複製代碼
awk使用printf格式化輸出

printf 格式說明符

格式符 含義
%s 打印字符串
%d 打印十進制數
%f 打印一個浮點數
%x 打印十六進制數
%o 打印八進制數
%e 打印數字的科學計數法形式
%c 打印單個字符的ASCII碼

printf 修飾符

修飾符 含義
- 左對齊
+ 右對齊
# 8進制顯示在前面加0,16進制顯示在前面加0X

上面演示的案例,咱們都是用print來作輸出(默認是輸出每行內容,用回車鍵做爲換行),如今咱們使用printf(默認沒有加任何的輸出分隔符)來進行格式化打印輸出

使用%s以字符串形式輸出/etc/passwd文件中第一列

$ awk -F: '{printf "%s\n",$1}' /etc/passwd
root
bin
daemon
...
複製代碼

使用 \n 來指定輸出每行的的分隔符

使用$s%f%d%x等多個格式符來輸出

$  awk -F: '{printf "%s %f %d %x\n",$1,$3,$3,$3}' /etc/passwd
sshd 74.000000 74 4a
postfix 89.000000 89 59
chrony 998.000000 998 3e6
vagrant 1000.000000 1000 3e8
vboxadd 997.000000 997 3e5
複製代碼

使用了不一樣的格式符,輸出了/etc/passwd文件中的$1,$3列,對於稍微有點強迫症患者的朋友來講,能夠看出輸出結果並不美觀,好比:每列都沒有對齊(向左或者向右),浮點數列沒有控制指定個數的精度等,下面咱們就來解決這個問題

$  awk -F: '{printf "%-20s %-0.2f \t\t %-20d %-20x\n",$1,$3,$3,$3}' /etc/passwd
sshd                 74.00 		     74                   4a
postfix              89.00 		     89                   59
chrony               998.00 		 998                  3e6
vagrant              1000.00 		 1000                 3e8
vboxadd              997.00 		 997                  3e5
複製代碼

咱們能夠在每一個格式符的前面加上數字,好比:%20s,表示這一列佔位20個字符

使用 %0.2f 來指定這一列輸出的精度,保留2位小數

使用 -格式符,表示輸出的結果向左對齊

關係運算符、布爾運算符和匹配正則表達式
運算符 含義
<、 <=、 >、 >=、 != 、 == 小於、小於等於...(關係運算符)
~ 匹配正則表達式
~! 不匹配正則表達式
|| 邏輯或
&& 邏輯與

匹配輸出第一列字符等於smile的行

$ awk '$1=="smile" {print $0}' score.txt
smile 55  78  80  34
複製代碼

匹配輸出第一列字符等於smile的行 ,或者第2列大於 80的行

$ awk '$1=="smile" || $2 > 80 {print $0}' score.txt
marry 90  49  23  14
smile 55  78  80  34
複製代碼

使用正則,匹配輸出包含44的行

$ awk '/44/ {print $0}' score.txt
join  44  55  66  24
jack  20  51  66  44
複製代碼

使用正則,匹配輸出不包含44的行

$ awk '!/44/ {print $0}' score.txt
marry 90  49  23  14
smile 55  78  80  34
複製代碼

使用正則,匹配輸出以join字符開頭的行到以jack字符開頭結束的行

$ awk '/^join/,/^jack/ {print $0}' score.txt
join  44  55  66  24
smile 55  78  80  34
jack  20  51  66  44
複製代碼

使用正則,匹配第1列字符包含jack而且最後一列大於等於34

$ awk '$1 ~ /jack/ && $NF >= 34 {print $0}' score.txt
jack  20  51  66  44
複製代碼

~ 表示模式開始;/ / 中表示的是匹配的具體模式

如今看下正則模式取反的示例

$ awk '$1 !~ /jack/ && $NF >= 24 {print $0}' score.txt
join  44  55  66  24
smile 55  78  80  34
複製代碼

!~ ,第1列不包含字符jack 而且最後列的值大於等於24

算術運算符
運算符 含義
+ 、 - 加、減
* 、/ 、 % 乘、除、求於
++、-- 增長或減小,做爲前綴或後綴,如(++x、x--)

咱們先來看一下簡單的加法和除法運算

$ awk 'BEGIN{ num1=10; num2=20; printf "%d %0.2f\n", num1+num2,num1/num2 }'
30 0.50
複製代碼

awk 聲明的變量能夠在任何多個花括號腳本中使用

計算/etc/services中空白行的數量

$ awk '/^$/ {sum++} END{print sum}' /etc/services
17
複製代碼
字符串函數
函數名 含義
length(str) 計算字符串長度
index(str1,str2) 在str1中查找str2的位置
tolower(str) 轉換爲小寫
toupper(str) 轉換爲大寫
substr(str,m,n) 從str的第m個字符開始,截取m位
split(str,arr,fs) 按fs切割字符,結果保存arr中
match(str,RE) 在str中按照RE查找

因爲字符串函數是咱們工做中經常使用的函數,比較簡單,下面咱們使用split()函數來作演示

$ awk 'BEGIN{ str="java#python#go"; split(str,arr,"#"); for(item in arr){ print arr[item] } }'
java
python
go
複製代碼

其中咱們使用了for循環來遍歷 arr 數組,下面咱們會講到

awk動做中使用條件及循環語句(可見awk是個腳本解釋器)

條件表達式

  • if語句

語法格式以下:

if(條件){
    動做
}
複製代碼

示例:

$ awk -F: '{if($3>100 && $3<1000) print $0}' /etc/passwd
複製代碼
  • if - else 語句

語法格式以下:

if(條件){
    動做
}else{
    動做
}
複製代碼

示例:

$ awk 'BEGIN { num = 11; if (num % 2 == 0) { printf "%d 是偶數\n", num }else { printf "%d 是奇數\n", num } }'
複製代碼
  • if - else - if 語句

語法格式以下:

if(條件){
    動做
}else if(條件){
    動做
}else{
    動做
}
複製代碼

示例:

$ awk  -F: '{ if($3<100) { print "系統用戶", $1 } else if($3>100 && $3 <900) { print "普通用戶", $1 } else { print "其它用戶", $1 } }'  /etc/passwd
複製代碼

循環語句

  • while 語句
while(條件){
    循環體
}
複製代碼

示例:

$ awk 'BEGIN {i=1; while(i<6){ print i; ++i } }'
複製代碼
  • do - while語句

語法格式:

do{
    循環體
}while(條件)
複製代碼

示例:

awk 'BEGIN{i=1;do{print i;i++}while(i<6)}'
複製代碼
  • for 語句

語法格式:

for(變量;條件;表達式){
    動做
}
複製代碼

示例:

$ awk 'BEGIN{ sum=0; for(i=1;i<=100;i++){ sum+=i } print sum }'
複製代碼
經常使用選項
選項 含義
-v 參數傳遞
-V 查看awk的版本號
-f 指定腳本文件
-F 指定分隔符

使用-v引入外部變量

$ a=1
$ b="spring is framework"
$ awk -v c="$a" -v d="$b" 'BEGIN{print c , d}'
複製代碼

把awk的執行動做寫在腳本中,使用-f指定腳本文件

$ vim print.awk
$ BEGIN{print c , d}
複製代碼

執行腳本文件:print.awk

awk -v c="$a" -v d="$b" -f print.awk
複製代碼

使用-F指定分隔符

咱們以前可使用內置變量FS來指定分隔符,好比:

$ awk 'BEGIN{FS=":"} {print $1}' /etc/passwd
複製代碼

如今等價於:

$ awk -F ":" '{print $1}'  /etc/passwd
# 或者
$ awk -F: '{print $1}'  /etc/passwd
複製代碼
相關文章
相關標籤/搜索