Shell_awk

一、awk簡(jiǎn)介

awk 是一種編程語(yǔ)言,用于在linux/unix下對(duì)文本和數(shù)據(jù)進(jìn)行處理。

數(shù)據(jù)可以來(lái)自標(biāo)準(zhǔn)輸入、一個(gè)或多個(gè)文件,或其它命令的輸出。

支持用戶自定義函數(shù)和動(dòng)態(tài)正則表達(dá)式等先進(jìn)功能,是linux/unix
下的一個(gè)強(qiáng)大編程工具。

在命令行中使用,但更多是作為腳本來(lái)使用。

awk的處理文本和數(shù)據(jù)的方式是這樣的,它逐行掃描文件,從第一行到最后一行,尋找匹配的特定模式的行,并在這些行上進(jìn)行你想要的操作。如果沒(méi)有指定處理動(dòng)作,則把匹配的行顯示到標(biāo)準(zhǔn)輸出(屏幕),如果沒(méi)有指定模式,則所有被操作所指定的行都被處理。

awk分別代表其作者姓氏的第一個(gè)字母。因?yàn)樗淖髡呤侨齻€(gè)人,分別是Alfred Aho、Brian Kernighan、Peter Weinberger。

gawk是awk的GNU版本,它提供了Bell實(shí)驗(yàn)室和GNU的一些擴(kuò)展。

二、awk的兩種形式語(yǔ)法格式

awk [options] 'commands' filenames

awk [options] -f awk-script-file filenames

options:

-F 對(duì)于每次處理的內(nèi)容,可以指定一個(gè)子定義的分隔符,默認(rèn)的分隔符是空白字符(空格或 tab 鍵 )

command:

BEGIN{}                        {}               END{}

處理所有內(nèi)容之前的動(dòng)作       處理內(nèi)容中的動(dòng)作   處理所有內(nèi)容之后的動(dòng)作

示例

 awk 'BEGIN{print "----開(kāi)始處理了---"} {print "ok"} END{print "----都處理完畢---"}' /etc/hosts
----開(kāi)始處理了---
ok
ok
ok
----都處理完畢---

BEGIN{} 通常用于定義一些變量,例如 BEGIN{FS=":";OFS="---"}

========================================================

三、awk工作原理

awk -F: '{print $1,$3}' /etc/passwd

(1)awk,會(huì)處理文件的每一個(gè)行,每次處理時(shí),使用一行作為輸入,并將這一行賦給內(nèi)部變量$0,每一行也可稱為一個(gè)記錄,以換行符結(jié)束

(2)然后,行被:(默認(rèn)為空格或制表符)分解成字段(或稱為域),每個(gè)字段存儲(chǔ)在已編號(hào)的變量中,從$1開(kāi)始,
最多達(dá)100個(gè)字段

(3)awk如何知道用空白字符來(lái)分隔字段的呢? 因?yàn)橛幸粋€(gè)內(nèi)部變量FS來(lái)確定字段分隔符。初始時(shí),F(xiàn)S賦為空白字符

(4)awk打印字段時(shí),將以內(nèi)置的方法使用 print 函數(shù)打印,awk 在打印出的字段間加上空格。這個(gè)空格是內(nèi)部的一個(gè)變量 OFS 輸出字段的分隔符, 逗號(hào) , 會(huì)和 OFS 進(jìn)行映射,通過(guò) OFS 可以控制這個(gè)輸出分隔符的值。

(5)awk輸出之后,將從文件中獲取另一行,并將其存儲(chǔ)在$0中,覆蓋原來(lái)的內(nèi)容,然后將新的字符串分隔成字段并進(jìn)行處理。該過(guò)程將持續(xù)到所有行處理完畢

========================================================

四、記錄與字段相關(guān)內(nèi)部變量:

man awk

$0 : awk變量 $0 保存當(dāng)前正在處理的行內(nèi)容
NR : 當(dāng)前正在處理的行是 awk 總共處理的行號(hào)。
FNR: 當(dāng)前正在處理的行在其文件中的行號(hào)。
NF :每行被處理時(shí)的總字段數(shù)
$NF: 當(dāng)前處理行的分隔后的最后一個(gè)字段的值
FS : 輸入行時(shí)的字段分隔符,默認(rèn)空格

awk 'BEGIN{FS=":"} {print $1,$3}' /etc/passwd

OFS : 輸出字段分隔符,默認(rèn)是一個(gè) 空格

awk 'BEGIN{FS=":"; OFS="+++"} /^root/{print $1,$2,$3,$4}' /etc/passwd

ORS 輸出記錄分隔符, 默認(rèn)是換行符.

示例

將文件每一行合并為一行

ORS默認(rèn)輸出一條記錄應(yīng)該回車(chē),但是這里是加了一個(gè)空格

awk 'BEGIN{ORS="  "} {print $0}' /etc/passwd 

五、格式化輸出:

printf 函數(shù)

awk -F: '{printf "%-15s %-10s %-15s\n", $1,$2,$3}' /etc/passwd
awk -F: '{printf "|%-15s| %-10s| %-15s|\n", $1,$2,$3}' /etc/passwd
  • %s 字符類型
  • %d 十進(jìn)制整數(shù)
  • %f 浮點(diǎn)類型
  • %-15s占15字符 - 表示左對(duì)齊,默認(rèn)是右對(duì)齊
  • printf 默認(rèn)不會(huì)在行尾自動(dòng)換行,加 \n

六、awk模式和動(dòng)作

任何 awk 語(yǔ)句都由 模式動(dòng)作 組成。

模式部分 決定動(dòng)作語(yǔ)句何時(shí)觸發(fā)及觸發(fā)事件。
如果省略模式部分,動(dòng)作將時(shí)刻保持執(zhí)行狀態(tài)。

模式可以是任何條件語(yǔ)句或復(fù)合語(yǔ)句或正則表達(dá)式。

模式可以是

正則表達(dá)式:

  • 將整行進(jìn)行正則匹配(包含):

就是當(dāng)前處理的行有沒(méi)有包含 指定的模式(書(shū)寫(xiě)的正則表達(dá)式)
/正則/ 正則需要寫(xiě)在雙斜線內(nèi)

awk '/^root/' /etc/passwd
awk '$0 ~ /^root/' /etc/passwd
awk '!/root/' /tec/ passwd
awk '$0 !~ /^root/' /etc/passwd
  • 將某一字段進(jìn)行正則匹配:

可以使用的匹配操作符(~!~
字段 ~ /正則/

awk -F: '$1 ~ /^alice/' /etc/passwd
awk -F: '$NF !~ /bash$/' /etc/passwd
  • 實(shí)現(xiàn) 字符串的完全相等需要使用 ==

字符串需要使用雙引號(hào)
!= 表示不等于

awk -F: '$NF == "/bin/bash"' /etc/passwd
awk -F: '$1 == "root"' /etc/passwd
  • 比較表達(dá)式:

比較表達(dá)式采用對(duì)文本進(jìn)行比較,只有當(dāng)條件為真,才執(zhí)行指定的動(dòng)作。
比較表達(dá)式使用關(guān)系運(yùn)算符,用于比較數(shù)字與字符串。

關(guān)系運(yùn)算符有
< 小于 例如 x<y
> 大于 x>y
<= 小于或等于 x<=y
== 等于 x==y

!= 不等于 x!=y
>= 大于等于 x>=y

示例

awk -F: '$3 == 0' /etc/passwd
awk -F: '$3 < 10' /etc/passwd


df -P | grep '/' |awk '$4 > 25000'
  • 條件表達(dá)式:
awk -F: '$3>300 {print $0}' /etc/passwd
awk -F: '{ if($3>300) print $0 }' /etc/passwd
awk -F: '{ if($3>300) {print $0} }' /etc/passwd
awk -F: '{ if($3>300) {print $3} else{print $1} }' /etc/passwd
  • 算術(shù)運(yùn)算:+, -, *, /, %(模: 取余), ^(冪:2^3)

可以在模式中執(zhí)行計(jì)算,awk都將按浮點(diǎn)數(shù)方式執(zhí)行算術(shù)運(yùn)算

awk -F: '$3 * 10 > 500' /etc/passwd
awk -F: '{ if($3*10>500){print $0} }' /etc/passwd
  • 邏輯操作符和復(fù)合模式

&& 邏輯與, 相當(dāng)于 并且
||邏輯或,相當(dāng)于 或者
! 邏輯非 , 取反

awk -F: '$1~/root/ && $3<=15' /etc/passwd
awk -F: '$1~/root/ || $3<=15' /etc/passwd
awk -F: '!($1~/root/ || $3<=15)' /etc/passwd
?  ~ cat passwd
root:x:0:0:root:/root:/bin/zsh
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:20:2:daemon:/sbin:/sbin/nologin
root:x:20:2:daemon:/sbin:/sbin/nologin
?  ~ awk -F: '!($1~/root/ || $3<=15){print $0}' passwd
daemon:x:20:2:daemon:/sbin:/sbin/nologin
?  ~ awk -F: '($1~/root/ || $3<=15){print $0}' passwd
root:x:0:0:root:/root:/bin/zsh
bin:x:1:1:bin:/bin:/sbin/nologin
root:x:20:2:daemon:/sbin:/sbin/nologin
  • 范圍模式, 模式之間用逗號(hào) , 隔開(kāi)

使用語(yǔ)法是: 起始表達(dá)式, 終止表達(dá)式

下面的意思是: 從開(kāi)頭是 bin 的行開(kāi)始匹配成功一直到含有 adm 的行結(jié)束匹配
也就是 開(kāi)頭是 bin 的行到含有 adm 的行 的所有內(nèi)容都符合匹配條件。

?  ~ awk -F: '/^bin/,/adm/ {print $0 }' /etc/passwd
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

生產(chǎn)實(shí)例:
統(tǒng)計(jì)日志中某個(gè)時(shí)間范圍的 IP 訪問(wèn)量,并進(jìn)行排序

部分日志

110.183.58.144 - - [10/May/2018:23:49:27 +0800] "GET http://app.znds.com/html/20180504/y222sks_2.2.3_dangbei.dangbei HTTP/1.1" 200 14306614 "-" "okhttp/3.4.1"
1.69.17.127 - - [10/May/2018:23:49:31 +0800] "GET http://app.znds.com/down/20180205/ttjs_3.0.0.1_dangbei.apk HTTP/1.1" 200 13819375 "-" "okhttp/3.4.1"
1.69.17.127 - - [10/May/2018:23:49:40 +0800] "GET http://app.znds.com/down/20180416/ttyj_1.1.6.0_dangbei.apk HTTP/1.1" 200 16597231 "-" "okhttp/3.4.1"
1.69.17.127 - - [10/May/2018:23:50:00 +0800] "GET http://app.znds.com/down/20170927/jydp_1.06.00_dangbei.apk HTTP/1.1" 200 36659203 "-" "okhttp/3.4.1"

具體實(shí)現(xiàn)

日志文件名:app.log

$ start_dt='10/May/2018:23:47:43
$ end_dt='10/May/2018:23:49:05'
$ awk -v st=${start_dt} -v ent=${end_dt} -F'[][ ]' '$5 == st,$5 == ent  {print $1}' app.log  |sort |uniq -c |sort -nr |head -n 10
     66 223.13.142.15
      6 110.183.13.212
      4 1.69.17.127
      1 113.25.94.69
      1 110.183.58.144

awk 正則示例:

匹配開(kāi)頭是 bin 的或者開(kāi)頭是 root 的行

?  ~ awk -F: '/^(bin|root)/' /etc/passwd
root:x:0:0:root:/root:/bin/zsh
bin:x:1:1:bin:/bin:/sbin/nologin

指定多個(gè)分隔符:[]

?  ~ echo "a b|c d| ||||e | |" |awk -F'[ |]' '{print $10}'
e
?  ~ echo "a b|c d| ||||e | |" |awk -F'[ |]+' '{print $5}'
e
awk -F'[][ ]+' '$4 ~ /^11\/Apr\/2020/, $4 ~ /^17\/Apr\/2020/ && $7 ~ /^\/star\/local\/app/ {j++}END{print "總訪問(wèn)量:"j,"平均:"j/7}' access.log


注意: 中括號(hào)內(nèi)的任意字符均視為普通字符, 比如 . * 都被看做是 普通字符。
例如:

$ echo "a.b*c" |awk -F'[.*]' '{print $1, $2,$3}'
a b c

七、awk 腳本編程

條件判斷

if語(yǔ)句

格式 { if (表達(dá)式) {語(yǔ)句; 語(yǔ)句; ...}}

awk -F: '{if($3==0) {print $1 " is administrator."}}' /etc/passwd
輸出: root is administrator.

# 統(tǒng)計(jì)系統(tǒng)級(jí)別用戶的數(shù)量
awk -F: '{if($3>0 && $3<1000){count++;}} END{print count}' /etc/passwd 
輸出: 22

if...else語(yǔ)句

格式 {if(表達(dá)式){語(yǔ)句;語(yǔ)句;...}else{語(yǔ)句;語(yǔ)句;...}}

awk -F: '{if($3==0){print $1} else {print $7}}' /etc/passwd

awk -F: '{ if($3==0){count++} else{i++} } END{print "管理員個(gè)數(shù): "count "系統(tǒng)用戶數(shù): "i}' /etc/passwd
輸入:
管理員個(gè)數(shù): 1系統(tǒng)用戶數(shù): 24

awk -F: '{ if($3==0){count++} else{i++} } END{print "管理員個(gè)數(shù): "count ; print  "系統(tǒng)用戶數(shù): "i}' /etc/passwd
輸出:
管理員個(gè)數(shù): 1
系統(tǒng)用戶數(shù): 24

if...else if...else語(yǔ)句

格式
{if(表達(dá)式1) {語(yǔ)句;語(yǔ)句;...} else if (表達(dá)式2) {語(yǔ)句;語(yǔ)句;...} else if(表達(dá)式3){語(yǔ)句;語(yǔ)句;...} else {語(yǔ)句;語(yǔ)句;...} }

awk -F: '{if($3==0){i++} else if($3>999){k++} else{j++}} END{print i; print k; print j}' /etc/passwd
輸出:
1
2
22

awk -F: '{if($3==0){i++} else if($3>999){k++} else{j++}} END{print "管理員個(gè)數(shù): "i; print "普通用個(gè)數(shù): "k; print "系統(tǒng)用戶: "j}' /etc/passwd
輸出:
管理員個(gè)數(shù): 1
普通用個(gè)數(shù): 2
系統(tǒng)用戶: 22

awk使用外部變量:

擴(kuò)展

方法一:awk參數(shù)-v(推薦使用,易讀)

[root@sharkyun ~]# w=hello
[root@sharkyun ~]# echo "hello world" | awk -v var=$w '$1 == var {print $1}'
hello

其他練習(xí)

[root@tianyun ~]# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/cl-root 2.8T 246G 2.5T 9% /
tmpfs 24G 20K 24G 1% /dev/shm
/dev/sda2 1014M 194M 821M 20% /boot

[root@tianyun ~]# df -h |awk '{ if(int($5)>5){print $6":"$5} }'
/:9%
/boot:20%

[root@tianyun ~]# i=10
[root@tianyun ~]# df -h |awk '{ if(int($5)>'''$i'''){print $6":"$5} }'
/boot:20%

作業(yè):
1. 取得網(wǎng)卡IP(除ipv6以外的所有IP)
2. 獲得內(nèi)存使用情況
3. 獲得磁盤(pán)使用情況
5. 打印出/etc/hosts文件的最后一個(gè)字段(按空格分隔)
6. 打印指定目錄下的目錄名

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、awk簡(jiǎn)介awk 是一種編程語(yǔ)言,用于在linux/unix下對(duì)文本和數(shù)據(jù)進(jìn)行處理。 數(shù)據(jù)可以來(lái)自標(biāo)準(zhǔn)輸入、一...
    光明_7c13閱讀 424評(píng)論 0 0
  • shell-awk awk簡(jiǎn)介 awk是一種編程語(yǔ)言,用于在linux下對(duì)文本和數(shù)據(jù)處理數(shù)據(jù)可以來(lái)自標(biāo)準(zhǔn)輸入、一個(gè)...
    _str_閱讀 188評(píng)論 0 1
  • 轉(zhuǎn)載 原文的排版和內(nèi)容都更加友好,并且詳細(xì),我只是在這里貼出了一部分留作自己以后參考和學(xué)習(xí),如希望更詳細(xì)了解AWK...
    XKirk閱讀 3,372評(píng)論 2 25
  • awk介紹awk變量printf命令:實(shí)現(xiàn)格式化輸出操作符awk patternawk actionawk數(shù)組aw...
    哈嘍別樣閱讀 1,743評(píng)論 0 4
  • 面向?qū)ο笞钪匾母拍罹褪穷悾–lass)和實(shí)例(Instance),必須牢記類是抽象的模板,比如Student類,...
    Aedda閱讀 228評(píng)論 0 1

友情鏈接更多精彩內(nèi)容