首頁 > 軟體

AWK簡單使用方法

2020-06-16 16:41:27

1. 命令格式

gawk [OPTIONS] 'program' FILES....
program:'PATTERN{ACTION}'
    一條awk命令中,PATTERN和ACTION,至少存在一個才可執行;
        缺少PATTERN,則對輸入行內容全部執行ACTION;
        缺少ACTION,則所有匹配上PATTERN的輸入行都會被輸出;
    在awk中使用分號“;”來分割語句;

2. awk的執行過程

awk讀取一行,進行模式匹配,匹配了就執行相應的動作,沒有匹配就忽略,讀取下一行,重複此動作.

3. 內建變數

FS:輸入檔案的field分隔符,預設是空白字元;
OFS:輸出檔案的field分隔符,預設是空白字元;
RS:輸入檔案record分隔符,預設是n;
ORS:輸入檔案record分隔符,預設是n;
NF:每行的field數量,{print NF}表示顯示當前行的field數量,{print $NF}表示顯示當前行的最後一個field;
NR:record數,對所有輸入行進行統一排序;
FNR:record數,對每個檔案的輸入行進行分別排序;
FILENAME:輸入檔案的名字;
ARGC:命令列中的引數個數;
ARGV:陣列,可以將當前命令列中的引數分別加入到ARGV這個陣列中,從0開始;
$1、$2、$3...$n:代表當前行中對應的field

4. 常用OPTION

-F:指定輸入分隔符;
-v:指定awk的變數;像FS、OSF、RS、ORS這些變數,就可以使用-v進行重新賦值;

5. 雙引號的作用

定義一個變數superuser的值為root,但是列印的時候,發現列印出了一個空行,並沒有實際內容
[root@CentOS7 ~]# awk 'BEGIN{superuser=root;print superuser}'
空行......

這是因為只有加上了雙引號才會被awk認為是字串,否則會被認為是變數。在上面這個例子中,想要為superuser賦值的是root字串,但是因為沒有加上雙引號,被awk認為root也是一個變數,但是awk中又不存在這個變數,所以最終為superuser的變數內容就是空。
所以在awk中定義變數應該是這種情況:
[root@centos7 ~]# awk 'BEGIN{superuser="root";print superuser}'
root

使用-v引數就沒有上面的限制
[root@centos7 ~]# awk -v superuser=root 'BEGIN{print superuser}'
root

6. ACTION

6.1 printf命令:按照指定的FORMAT進行格式化輸出;

格式化輸出:printf FORMAT, item1, item2, ...
FORMAT:FORMAT是一個字串, 它包含按字面列印的文字, 中間散布著格式說明符, 格式說明符用於說明如何列印值. 一個格式說明符是一個%, 後面跟著幾個字元, 這些字元控制一個value 的輸出格式. 第一個格式說明符說明item1 的輸出格式, 第二個格式說明符說明item2 的輸出格式, 依次類推. 於是, 格式說明符的數量應該和被列印的item 一樣多;

printf不會自動產生換行符,必須手動建立;

格式符

%s:顯示字串;
%i,%d:顯示十進位制整數;

修飾符

#[.#]:第一個#控制顯示的寬度,第二個#表示小數點後的精度;
    例如:%3.1f
-減號:左對齊(不加減號,預設為右對齊);
+加號:顯示數值的符號;

範例

例如:使用printf列印/etc/passwd中的$1和$3
[Allen@centos7 ~]$ head /etc/passwd | awk -F: '{printf "Username: %-12sUID: %-8in",$1,$3}'
Username: root        UID: 0       
Username: bin         UID: 1       
Username: daemon      UID: 2       
Username: adm         UID: 3       
Username: lp          UID: 4       
Username: sync        UID: 5       
Username: shutdown    UID: 6       
Username: halt        UID: 7       
Username: mail        UID: 8       
Username: operator    UID: 11       

6.2 if-else

語法:'if(condition){statements}[else{statements}]'
使用場景:對awk取得的整行或某個欄位做條件判斷;

範例

例如:當$3大於等於1000時,列印$1;
[Allen@centos7 ~]$ awk -F: '{if($3>=1000) printf "%sn",$1}' /etc/passwd
Allen
logstash

例如:當$3大於等於1000時,列印為CommonUser: $1;否則列印為Systemuser: $1;
[Allen@centos7 ~]$ awk -F: '{if($3>=1000) {printf "CommonUser: %-15sn",$1} else {printf "SystemUser: %sn",$1}}' /etc/passwd | head 
SystemUser: root
SystemUser: bin
SystemUser: daemon
SystemUser: adm
SystemUser: lp
SystemUser: sync
SystemUser: shutdown
SystemUser: halt
SystemUser: mail
SystemUser: operator

6.3 while

語法:while(condition){statements}
使用場景:對一行內的多個欄位逐一進行類似處理時使用;或對陣列中的各元素逐一處理時使用;

範例

例如:以空格開頭0次或多次,後跟linux16的行,以空格為分隔符,顯示每行中各欄位的長度;
[Allen@centos7 ~]$ sudo awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {printf "%-55s%in",$i,length($i); i++}}' /boot/grub2/grub.cfg
linux16                                                7
/vmlinuz-4.18.14-1.el7                                 22
root=UUID=2073d1d0-1eab-4a58-900e-b9bfd178278f         46
ro                                                     2
rhgb                                                   4
quiet                                                  5
linux16                                                7
/vmlinuz-3.10.0-693.el7.x86_64                         30
root=UUID=2073d1d0-1eab-4a58-900e-b9bfd178278f         46
ro                                                     2
rhgb                                                   4
quiet                                                  5

例如:以空格開頭0次或多次,後跟linux16的行,以空格為分隔符,只顯示每行中欄位的長度>=7的欄位;
[Allen@centos7 ~]$ sudo awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {if(length($i)>=7) {printf "%-55s%in",$i,length($i)}; i++}}' /boot/grub2/grub.cfg
linux16                                                7
/vmlinuz-4.18.14-1.el7                                 22
root=UUID=2073d1d0-1eab-4a58-900e-b9bfd178278f         46
linux16                                                7
/vmlinuz-3.10.0-693.el7.x86_64                         30
root=UUID=2073d1d0-1eab-4a58-900e-b9bfd178278f         46

6.4 for

語法:for(expr1;expr2;expr3) statement
特殊用法:for(var in arry) statements        ##用於遍歷陣列中的元素

範例

例如:以空格開頭0次或多次,後跟linux16的行,以空格為分隔符,顯示每行中各欄位的長度;
[Allen@centos7 ~]$ sudo awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) printf "%-55s%in",$i,length($i)}' /etc/grub2.cfg 
linux16                                                7
/vmlinuz-4.18.14-1.el7                                 22
root=UUID=2073d1d0-1eab-4a58-900e-b9bfd178278f         46
ro                                                     2
rhgb                                                   4
quiet                                                  5
linux16                                                7
/vmlinuz-3.10.0-693.el7.x86_64                         30
root=UUID=2073d1d0-1eab-4a58-900e-b9bfd178278f         46
ro                                                     2
rhgb                                                   4
quiet                                                  5

7. 描述awk函數範例(至少3例)

length([s]):統計s的字元數量;
sub(r,s):將當前行中最左邊第一個能被r匹配的內容,替換成s;
sub(r,s,t):將t中最左邊第一個能被r匹配的內容,替換成s;
gsub(r,s):將當前行中能被r匹配的內容,全部替換成s;
gsub(r,s,t ):將t中能被r匹配的內容,全部替換成s;
split(s,a):將s分割,然後分別加入到陣列a中(awk命令中沒有指定FS則使用預設的空格做為分隔符);
split(s,a,fs):使用fs將s分割,然後分別加入到陣列a中;
sprintf(format,expr1,expr2,exprn):返回一個字串(不列印),這個字串按指定的format格式化expr1..exprn
genline:讀取下一行,重新設定NF、NR、FNR;

範例

範例1:length函數
[root@centos7 ~]# awk 'BEGIN{superuser="root";print length(superuser)}'
4

範例2:sub和gsub函數
[root@centos7 ~]# echo "hello World" | awk '{sub("l",1);print $0}'
he1lo World
[root@centos7 ~]# echo "hello World" | awk '{sub("l",1,$1);print $0}'
he1lo World

[root@centos7 ~]# echo "hello World" | awk '{gsub("l",1);print $0}'
he11o Wor1d
[root@centos7 ~]# echo "hello World" | awk '{gsub("l",1,$1);print $0}'
he11o World

範例3:split函數
陣列下標從1開始
[root@centos7 ~]# awk -F/ 'BEGIN{i="China/America/Britain";split(i,countrys);for(c=1;c<=3;c++)print countrys[c]}'
China
America
Britain
[root@centos7 ~]# awk 'BEGIN{i="China/America/Britain";split(i,countrys,"/");for(c=1;c<=3;c++)print countrys[c]}'
China
America
Britain

範例4:sprintf函數
[root@centos7 ~]# awk -F: 'NR>=1&&NR<=5{x=sprintf("%-10s%-5d",$1,$3);print x}' /etc/passwd
root      0    
bin       1    
daemon    2    
adm       3    
lp        4  

範例5:getline函數
列印出從1到10之間的偶數
awk首先讀取到了第一行,就是1,然後getline,就得到了1下面的第二行,就是2,因為getline之後,awk會改變對應的NF,NR,FNR和$0等內部變數,所以此時的$0的值就不再是1,而是2了,然後將它列印出來。以此類推,就可以得到下面的結果。
[Allen@centos7 ~]$ seq 10 | awk '{getline; print $0}'
2
4
6
8
10

列印出從1到10之間的奇數
因為getline在print $0之後,此時的$0仍然是第一行。然後getline,$0變成了下一行2。依次類推,就列印出了奇數行。
[Allen@centos7 ~]$ seq 10 | awk '{print $0; getline}'
1
3
5
7
9

IT145.com E-mail:sddin#qq.com