awk應用案例

  • awk並不是一個簡單命令,它實際上是一門編程語言,適合處理文本類數據,awk處理文本是以記錄(文本中的行)爲單位的,它會遍歷文件的每條記錄並進行處理linux

  • awk語法格式: awk 'Pattern {Action}' filenamenginx

  • awk工做原理:awk讀取一條記錄,並將記錄賦值給內部變量$0,記錄被分隔符分割成多個字段,每一個字段存儲到指定編號的變量中,從$1開始,(awk內部變量FS用來指定字段分隔符,默認爲空格,包含製表符和空格符,也可用-F來自定義分隔符),對於每一條記錄,按照給定的Pattern進行匹配,匹配成功則執行Action,匹配失敗,則不執行Action,其中Pattern和Action都是可選的,但必須提供其中一個,若是未指定Pattern,則對全部輸入行都執行Action,若是未指定Action,則輸出匹配行的內容git

  • $0 表示文本中的一條記錄即一行內容redis

[root@linux01 ~]#  head -n5 /etc/passwd| awk '{print $0}'
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
  • 截取其中若干列內容,awk默認空格爲分隔符,若是要改變分隔符可用"-F"選項自定義
[root@linux01 ~]#  head -n5 /etc/passwd| awk -F: '{print $1,$3}'
root 0
bin 1
daemon 2
adm 3
lp 4
  • 添加修飾內容,BEGIN和END是awk關鍵字,前者表示在awk對文件處理前首先被執行,後者表示在awk對文件處理後被執行
[root@linux01 ~]#  head -n5 /etc/passwd| awk -F: 'BEGIN {print "=====begin====="} {print $1,$3} END {print "=====end====="}'
=====begin=====
root 0
bin 1
daemon 2
adm 3
lp 4
=====end=====
  • awk可實現數學計算,$3+$4表示以:(冒號)分隔的第三和第四列之和
[root@linux01 ~]#  head -n5 /etc/passwd| awk -F: 'BEGIN {print "=====begin====="} {print $1,$2,$3+$4} END {print "=====end====="}'
=====begin=====
root x 0
bin x 2
daemon x 4
adm x 7
lp x 11
=====end=====
  • 針對輸出結果進行過濾,~表示匹配意思
[root@linux01 ~]#  head -n5 /etc/passwd| awk -F: 'BEGIN {print "=====begin====="} $1~/lp/ {print $1,$2,$3+$4} END {print "=====end====="}'
=====begin=====
lp x 11
=====end=====
  • 巧妙顯示奇/偶行,'NR%2==0 {next}'做爲awk的Pattern匹配部分,其中NR表示當前記錄的行號,整句表示NR被整除爲TRUE的話,則執行next動做,而遇到next,就會忽略後面的Action部分,直接進入下一行處理,因此顯示爲奇數行輸出
[root@linux01 ~]# cat -n file1.txt    
     1	test 1
     2	one two three proce
     3	test 2 
     4	test test file
[root@linux01 ~]# awk 'NR%2==0 {next} {print NR,$0}' file1.txt 
1 test 1
3 test 2 
[root@linux01 ~]# awk 'NR%2!=0 {next} {print NR,$0}' file1.txt 
2 one two three proce
4 test test file
  • 固定行合併,經過第一部分和第二部分語句,能夠實現3行一組的前兩行內容存放到變量T中,當處理第三行時,就會把全部以前存儲的內容都輸出來,而後清空變量T,再進行下一組數據處理
[root@linux01 ~]# cat -n file1.txt 
     1	test 1
     2	one two three proce
     3	test 2 
     4	test test file
     5	wsr239wfgrte
     6	fw9efs0art4
     7	4tesd8w40-sdgd
     8	43q8wsfjwrskdpoht
     9	rear8ut9spgoog
    10	45678
    11	s34otjvsa;
    12	4su02q9jdgopro[
[root@linux01 ~]# awk 'NR%3!=0 {T=(T" "$0);next} {print T,$0;T=""}' file1.txt 
 test 1 one two three proce test 2 
 test test file wsr239wfgrte fw9efs0art4
 4tesd8w40-sdgd 43q8wsfjwrskdpoht rear8ut9spgoog
 45678 s34otjvsa; 4su02q9jdgopro[
  • 以上案例存在一個小問題,文件行數恰好是3的倍數,若是不是3的倍數呢...
[root@linux01 ~]# cat -n file1.txt 
     1	test 1
     2	one two three proce
     3	test 2 
     4	test test file
     5	wsr239wfgrte
     6	fw9efs0art4
     7	4tesd8w40-sdgd
     8	43q8wsfjwrskdpoht
     9	rear8ut9spgoog
    10	45678
    11	s34otjvsa;
[root@linux01 ~]# awk 'NR%3!=0 {T=(T" "$0);next} {print T,$0;T=""}' file1.txt     -->發現丟失了10,11行內容
 test 1 one two three proce test 2 
 test test file wsr239wfgrte fw9efs0art4
 4tesd8w40-sdgd 43q8wsfjwrskdpoht rear8ut9spgoog

[root@linux01 ~]# awk 'NR%3!=0 {T=(T" "$0);next} {print T,$0;T=""} END {print T}' file1.txt     -->改進後命令,由於文本行數不是3的倍數時,不是3的倍數的最後一組記錄存放在變量T中,只要咱們把它輸出便可完美解決此問題
 test 1 one two three proce test 2 
 test test file wsr239wfgrte fw9efs0art4
 4tesd8w40-sdgd 43q8wsfjwrskdpoht rear8ut9spgoog
 45678 s34otjvsa;
  • 不定行數合併,在於用正則來找規律分組
[root@linux01 ~]# cat -n file1.txt 
     1	test 1
     2	one two three proce
     3	test 2
     4	abc bca file
     5	wsr239wfgrte
     6	fw9efs0art4
     7	4tesd8w40-sdgd
     8	test 3
     9	43q8wsfjwrskdpoht
    10	rear8ut9spgoog
    11	45678
    12	s34otjvsa;
    13	test 4
[root@linux01 ~]# awk 'BEGIN {T=""} /test/ {print T;T=$0;next} {T=T" "$0} END {print T}' file1.txt 

test 1 one two three proce
test 2 abc bca file wsr239wfgrte fw9efs0art4 4tesd8w40-sdgd
test 3 43q8wsfjwrskdpoht rear8ut9spgoog 45678 s34otjvsa;
test 4
  • 合併全部行
[root@linux01 ~]# cat -n file1.txt 
     1	test 1
     2	one two three proce
     3	test 2
     4	abc bca file
     5	wsr239wfgrte
     6	fw9efs0art4
     7	4tesd8w40-sdgd
     8	test 3
     9	43q8wsfjwrskdpoht
    10	rear8ut9spgoog
    11	45678
    12	s34otjvsa;
    13	test 4
[root@linux01 ~]# awk '{T=T" "$0} END {print T}' file1.txt 
 test 1 one two three proce test 2 abc bca file wsr239wfgrte fw9efs0art4 4tesd8w40-sdgd test 3 43q8wsfjwrskdpoht rear8ut9spgoog 45678 s34otjvsa; test 4

** 輸出多個文件內容sql

[root@linux01 ~]# cat new.txt 
root:x:0:0:root:/root:/bin/bash
this is a file
good ha 
feng file
[root@linux01 ~]# cat test.txt 
/0/,/3/p
sfwefov
w342re0k
fewfklfs;ar
sfd9wo4sd
[root@linux01 ~]# awk '{print $0}' new.txt test.txt 
root:x:0:0:root:/root:/bin/bash
this is a file
good ha 
feng file
/0/,/3/p
sfwefov
w342re0k
fewfklfs;ar
sfd9wo4sd

** 輸出第一個文件的第一行和第二個文件的第二行內容,NR表示已讀記錄數,不論有幾個文件,每讀一條記錄,值就會加1,FNR表示當前文件已讀記錄數,每讀取一條記錄,值就會加1,但更換文件後,該變量會從新從零開始,NR==FNR時,表示awk正在處理第一個文件,NR>FNR時,表示正在處理第二個文件,FILENAME表示當前處理文件的文件名shell

[root@linux01 ~]# cat new.txt 
root:x:0:0:root:/root:/bin/bash
this is a file
good ha 
feng file
[root@linux01 ~]# cat test.txt 
/0/,/3/p
sfwefov
w342re0k
fewfklfs;ar
sfd9wo4sd
[root@linux01 ~]# awk 'NR==FNR&&FNR==1 {print FILENAME,$0} NR>FNR&&FNR==2 {print FILENAME,$0}' n
ew.txt test.txt 
new.txt root:x:0:0:root:/root:/bin/bash
test.txt sfwefov

** 上面的案例在處理兩個以上文件時有所侷限,咱們能夠轉變一下思路,引入一個環境變量,叫作ARGIND,用來指示當前處理的文件編號編程

[root@linux01 ~]# cat new.txt 
root:x:0:0:root:/root:/bin/bash
this is a file
good ha 
feng file
[root@linux01 ~]# cat test.txt 
/0/,/3/p
sfwefov
w342re0k
fewfklfs;ar
sfd9wo4sd
[root@linux01 ~]# cat file1.txt 
test 1
one two three proce
test 2
abc bca file
wsr239wfgrte
fw9efs0art4
4tesd8w40-sdgd
test 3
43q8wsfjwrskdpoht
rear8ut9spgoog
45678
s34otjvsa;
test 4
[root@linux01 ~]# awk 'ARGIND==1&&FNR==1 {print FILENAME,$0} ARGIND==2&&FNR==2 {print FILENAME,$0} ARGIND==3&&FNR==3 {print FILENAME,$0}' new.txt test.txt file1.txt 
new.txt root:x:0:0:root:/root:/bin/bash
test.txt sfwefov
file1.txt test 2

** 上面案例還能夠用相似數組方式處理,ARGV表示命令行參數的數組vim

[root@linux01 ~]# cat new.txt 
root:x:0:0:root:/root:/bin/bash
this is a file
good ha 
feng file
[root@linux01 ~]# cat test.txt 
/0/,/3/p
sfwefov
w342re0k
fewfklfs;ar
sfd9wo4sd
[root@linux01 ~]# cat file1.txt 
test 1
one two three proce
test 2
abc bca file
wsr239wfgrte
fw9efs0art4
4tesd8w40-sdgd
test 3
43q8wsfjwrskdpoht
rear8ut9spgoog
45678
s34otjvsa;
test 4
[root@linux01 ~]# awk 'FILENAME==ARGV[1]&&FNR==1 {print FILENAME,$0} FILENAME==ARGV[2]&&FNR==2 {print FILENAME,$0} FILENAME==ARGV[3]&&FNR==3 {print FILENAME,$0}' new.txt test.txt file1.txt 
new.txt root:x:0:0:root:/root:/bin/bash
test.txt sfwefov
file1.txt test 2

** 咱們想用/etc/shadow文件中的加密字段替換/etc/passwd文件中的x密碼字段,OFS表示輸出時指定的分隔符,FS表示字段分隔符,讀取shadow文件時,把加密字段內容放入下標爲用戶列的數組中,再讀取passwd文件時,再賦值給x密碼字段,輸出修改後內容便可數組

[root@linux01 ~]# awk 'BEGIN {OFS=FS=":"} NR==FNR {a[$1]=$2} NR>FNR {$2=a[$1];print}' /etc/shadow /etc/passwd
root:$6$CYXcNKe6hd7jzBgx$cA8WUgq/mYEymotuD0YAJRBkYtgc5nc8MFfPokHjC0LrfmHGtSIx3zE0YS5ML2Dc2YaG8Kl7khssL0faik7AS.:0:0:root:/root:/bin/bash
bin:*:1:1:bin:/bin:/sbin/nologin
daemon:*:2:2:daemon:/sbin:/sbin/nologin
adm:*:3:4:adm:/var/adm:/sbin/nologin
lp:*:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:*:5:0:sync:/sbin:/bin/sync
shutdown:*:6:0:shutdown:/sbin:/sbin/shutdown
halt:*:7:0:halt:/sbin:/sbin/halt
mail:*:8:12:mail:/var/spool/mail:/sbin/nologin
operator:*:11:0:operator:/root:/sbin/nologin
games:*:12:100:games:/usr/games:/sbin/nologin
ftp:*:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:*:99:99:Nobody:/:/sbin/nologin
systemd-bus-proxy:!!:999:997:systemd Bus Proxy:/:/sbin/nologin
systemd-network:!!:192:192:systemd Network Management:/:/sbin/nologin
dbus:!!:81:81:System message bus:/:/sbin/nologin
polkitd:!!:998:996:User for polkitd:/:/sbin/nologin
tss:!!:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
postfix:!!:89:89::/var/spool/postfix:/sbin/nologin
sshd:!!:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
chrony:!!:997:995::/var/lib/chrony:/sbin/nologin
jenkins:!!:996:994:Jenkins Automation Server:/var/lib/jenkins:/bin/false
gitlab-www:!!:995:992::/var/opt/gitlab/nginx:/bin/false
git:!!:994:991::/var/opt/gitlab:/bin/sh
gitlab-redis:!!:993:990::/var/opt/gitlab/redis:/bin/false
gitlab-psql:!!:992:989::/var/opt/gitlab/postgresql:/bin/sh
gitlab-prometheus:!!:991:988::/var/opt/gitlab/prometheus:/bin/sh
virftp:!!:1000:1000::/home/virftp:/sbin/nologin

** getline操做文件案例,你會以爲getline命令也能夠實現奇偶行輸出功能,但不建議這樣用,由於有缺憾,只有在處理文本總數是偶數行時適用,在awk中,當getline左右沒有"<" "|"時,getline是對當前打開文件操做,表示讀取當前行的下一行內容,並把數據賦值給$0,同時更新NF,NR,FNRbash

[root@linux01 ~]# seq 10|awk '{getline;print}'
2
4
6
8
10
[root@linux01 ~]# seq 10|awk '{print;getline}'
1
3
5
7
9
[root@linux01 ~]# seq 10|awk '{print;getline;print}'
1
2
3
4
5
6
7
8
9
10
[root@linux01 ~]# seq 11|awk '{getline;print}'    -->若是換成奇數行內容getline命令就會出錯了
2
4
6
8
10
11

** 在awk中,當getline左右有重定向符"< 、<<"或"|"時,getline做用於其後的輸入文件而不是當前打開的文件,因爲輸入文件是新打開的,並無被awk讀取,所以getline返回的是該文件的第一行,而不是當前讀取文件的隔行內容,getline的返回值: 1:表示正常讀取一行數據;0:表示到了文件末尾;-1:表示讀取遇到錯誤;所以案例中當處理test文件第一行內容時,getline會讀取文件num的內容,直至文件指針指向文件末尾,之後每處理一行文件test的數據,getline返回值都是0,因此不會再有文件num的內容輸出,getline重定向文件時,後面必須跟字符串類型,所以文件名必定要加雙引號

[root@linux01 ~]# cat test.txt 
1 /sdfa/,/ewra/p
2 sfwefov
3 wsfresdfwek
4 fewfklfs;ar
5 sfdsfawowesd
[root@linux01 ~]# cat num.txt 
10 20 30
40 50 60
[root@linux01 ~]# awk '' test.txt 
[root@linux01 ~]# awk '{print $0;while((getline < "num.txt") > 0) print $0}' test.txt 
1 /sdfa/,/ewra/p
10 20 30
40 50 60
2 sfwefov
3 wsfresdfwek
4 fewfklfs;ar
5 sfdsfawowesd

** 用system調用shell,awk經過system()函數來調用shell的程序

[root@linux01 ~]# awk 'BEGIN {system("ls -al")}'
總用量 136
dr-xr-x---.  8 root root  4096 12月 11 15:13 .
dr-xr-xr-x. 18 root root   256 11月 23 21:53 ..
-rw-r-----   1 root root  1502 11月 24 21:29 1.log
-rw-r--r--   1 root root   161 11月 20 10:38 adduser.sh
-rw-------.  1 root root  1422 11月 14 18:11 anaconda-ks.cfg
-rw-------.  1 root root 18728 12月 11 11:56 .bash_history
-rw-r--r--.  1 root root    18 12月 29 2013 .bash_logout
-rw-r--r--.  1 root root   176 12月 29 2013 .bash_profile
-rw-r--r--.  1 root root   176 12月 29 2013 .bashrc
drwxr-xr-x   3 root root    18 11月 28 23:08 .config
-rw-r--r--.  1 root root   100 12月 29 2013 .cshrc
-rw-r--r--   1 root root    91 11月 20 10:33 deluser.sh
-rw-r--r--   1 root root   151 12月 10 12:12 file1.txt
-rw-r--r--   1 root root    56 11月 24 01:08 .gitconfig
-rw-r--r--   1 root root  4360 11月 22 15:11 :ii:wq
-rw-r--r--   1 root root    20 12月 11 10:59 k1.txt
-rw-------   1 root root    54 11月 23 01:29 .lesshst
drwxr-xr-x   3 root root    19 11月 28 23:08 .local
drwxr-x---   2 root root    19 11月 24 21:28 logs
-rw-r--r--   1 root root    66 12月 10 21:33 new.txt
-rw-r--r--   1 root root    18 12月 11 15:13 num.txt
-rw-r--r--   1 root root  1494 11月 23 17:38 passwd
-rw-r--r--   1 root root 12288 11月 27 14:54 .passwd.swp
drwxr-----   3 root root    19 11月 20 20:47 .pki
-rw-------   1 root root  1024 11月 29 00:45 .rnd
drwxr-xr-x   3 root root    32 11月 23 21:38 sample
drwx------   2 root root    82 11月 23 16:34 .ssh
-rw-r--r--.  1 root root   129 12月 29 2013 .tcshrc
-rw-r--r--   1 root root    43 11月 22 11:27 tee
-rw-r--r--   1 root root    70 12月 11 11:40 test.txt
-rw-------   1 root root  5627 12月 10 12:12 .viminfo
-rw-------   1 root root  4286 11月 27 18:01 .viminfo.tmp
相關文章
相關標籤/搜索