## 1. awk簡介
awk是一種編程語言,用于在linux/unix下對文本和數據進行處理。數據可以來自標準輸入、一個或多個文件,或其它命令的輸出。它支持用戶自定義函數和動態正則表達式等先進功能,是linux/unix下的一個強大編程工具。它在命令行中使用,但更多是作為腳本來使用。awk的處理文本和數據的方式是這樣的,它逐行掃描文件,從第一行到最后一行,尋找匹配的特定模式的行,并在這些行上進行你想要的操作。如果沒有指定處理動作,則把匹配的行顯示到標準輸出(屏幕),如果沒有指定模式,則所有被操作所指定的行都被處理。awk分別代表其作者姓氏的第一個字母。因為它的作者是三個人,分別是Alfred Aho、Brian Kernighan、Peter Weinberger。gawk是awk的GNU版本,它提供了Bell實驗室和GNU的一些擴展。下面介紹的awk是以GUN的gawk為例的,在linux系統中已把awk鏈接到gawk,所以下面全部以awk進行介紹。
## 2. awk命令格式和選項
### 2.1 awk的語法有兩種形式
~~~
awk [options] 'script' var=value file(s)
awk [options] -f scriptfile var=value file(s)
~~~
PATTERN:匹配模式
action:print, printf(可以自定義打印格式)

### 2.2 命令選項
~~~
-F fs or --field-separator fs
指定輸入文件的分隔符,fs是一個字符串或者是一個正則表達式,如-F:、-F ab。
-v var=value or --asign var=value
賦值一個用戶定義變量。
-f scripfile or --file scriptfile
從腳本文件中讀取awk命令。
-W help or --help, -W usage or --usage
打印全部awk選項和每個選項的簡短說明。
-W re-interval or --re-inerval
允許間隔正則表達式的使用,參考(grep中的Posix字符類),如括號表達式[[:alpha:]]。
-W source program-text or --source program-text
使用program-text作為源代碼,可與-f命令混用。
-W version or --version
打印bug報告信息的版本。
~~~
## 3. 模式和操作
### 3.1 awk腳本是由模式和操作組成的
~~~
pattern {action} 如$ awk '/root/' test,或$ awk '$3 < 100' test
~~~
兩者是可選的,如果沒有模式,則action應用到全部記錄,如果沒有action,則輸出匹配全部記錄。默認情況下,每一個輸入行都是一條記錄,但用戶可通過RS變量指定不同的分隔符進行分隔。
模式
~~~
/正則表達式/:使用通配符的擴展集。
關系表達式:可以用下面運算符表中的關系運算符進行操作,可以是字符串或數字的比較,如$2>%1選擇第二個字段比第一個字段長的行。
模式匹配表達式:用運算符~(匹配)和~!(不匹配)。
模式:指定一個行的范圍。該語法不能包括BEGIN和END模式。
BEGIN:讓用戶指定在第一條輸入記錄被處理之前所發生的動作,通常可在這里設置全局變量。
END:讓用戶在最后一條輸入記錄被讀取之后發生的動作。
~~~
### 3.2 操作
操作由一個或多個命令、函數、表達式組成,之間由換行符或分號隔開,并位于大括號內。主要有四部份:
變量或數組賦值
輸出命令
內置函數
控制流命令
## 4 awk變量
### 4.1 awk內置變量之記錄變量
~~~
FS: field separator,讀取文件本時,所使用字段分隔符;(-F),默認為空格
RS: Record separator,輸入文本信息所使用的換行符;
OFS: Output Filed Separator,輸出文本時,所使用字段分隔符;默認為空格
ORS:Output Row Separator,輸出文本時,所使用行分隔符;
~~~
### 4.2 awk內置變量之數據變量
~~~
NR: The number of input records,awk命令已經處理的記錄數;如果有多個文件,這個數目會把處理的多個文件中行統一計數;相當于生成序號
FNR: 與NR不同的是,FNR用于記錄正處理的行是當前這一文件中被總共處理的行數;
NF:Number of Field,當前記錄的field個數;
~~~
~~~
awk '{print NF}' test.txt ;統計當前行的字段數
awk '{print $NF}' test.txt ;顯示當前行最后一個字段
~~~
~~~
ARGV: 數組,保存命令行本身這個字符串,如awk '{print $0}' a.txt b.txt這個命令中,ARGV[0]保存awk,ARGV[1]保存a.txt;
ARGC: awk命令的參數的個數;
FILENAME: awk命令所處理的文件的名稱;
ENVIRON:當前shell環境變量及其值的關聯數組;
~~~
### 4.3 用戶自定義變量
gawk允許用戶自定義自己的變量以便在程序代碼中使用,變量名命名規則與大多數編程語言相同,只能使用字母、數字和下劃線,且不能以數字開頭。gawk變量名稱區分字符大小寫。
* 在腳本中賦值變量
在gawk中給變量賦值使用賦值語句進行,例如:
~~~
awk 'BEGIN{var="variable testing";print var}'
~~~
* 在命令行中使用賦值變量
gawk命令也可以在“腳本”外為變量賦值,并在腳本中進行引用。例如,上述的例子還可以改寫為:
~~~
awk -v var="variable testing" 'BEGIN{print var}'
~~~
## 5 awk的操作符

## 6 匹配操作符(~)
用來在記錄或者域內匹配正則表達式。如$ awk '$1 ~/^root/' test將顯示test文件第一列中以root開頭的行。
## 7 比較表達式
`conditional expression1 ? expression2: expression3`,例如:`$ awk '{max = {$1 > $3} ? $1: $3: print max}' test`。如果第一個域大于第三個域,$1就賦值給max,否則$3就賦值給max。
~~~
$ awk '$1 + $2 < 100' test。如果第一和第二個域相加大于100,則打印這些行。
$ awk '$1 > 5 && $2 < 10' test,如果第一個域大于5,并且第二個域小于10,則打印這些行。
~~~
## 8 print
print的使用格式
print item1, item2, ...
>[info] 各項目之間使用逗號隔開,而輸出時則以空白字符分隔;
輸出的item可以為字符串或數值、當前記錄的字段(如$1)、變量或awk的表達式;數值會先轉換為字符串,而后再輸出;
print命令后面的item可以省略,此時其功能相當于print $0, 因此,如果想輸出空白行,則需要使用print "";
~~~
awk 'BEGIN { print "line one\nline two\nline three" }'
awk -F: '{ print $1, $3 }' /etc/passwd
awk 'BEGIN {FS=":";OFS="@"} { print $1, $3 }' /etc/passwd
~~~
## 9 printf
printf命令的使用格式
printf format, item1, item2, ...
要點:
>[info]其與print命令的最大不同是,printf需要指定format;
format用于指定后面的每個item的輸出格式;
printf語句不會自動打印換行符;\n
### 9.1 format
格式的指示符都以%開頭,后跟一個字符;如下:
~~~
%c: 顯示字符的ASCII碼;
%d, %i:十進制整數;int
%e, %E:科學計數法顯示數值;
%f: 顯示浮點數;
%g, %G: 以科學計數法的格式或浮點數的格式顯示數值;
%s: 顯示字符串;string
%u: 無符號整數;
%%: 顯示%自身;
~~~
### 9.2 修飾符
~~~
N: 顯示寬度;
-: 左對齊;
+:顯示數值符號;
~~~
### 例子
~~~
awk -F: '{printf "%-15s %d\n",$1,$3}' /etc/passwd
awk -F: 'BEGIN{printf "%-15s%-10s\n","USER","ID"}{printf "%-15s%-10i\n",$1,$3}' /etc/passwd
awk -F: 'BEGIN { printf "%-15s %-15s\n","user","uid";print "----------------------"} { printf "%-15s %-15d\n",$1,$3} END { print "----------------------" }' /etc/passwd
~~~
## 10 awk編程
### if-else
~~~
if (condition) {then-body} else {[ else-body ]}
~~~
~~~
awk -F: '{if ($1=="root") printf "%-15s: %s\n", $1,"Admin"; else printf "%-15s: %s\n", $1, "Common User"}' /etc/passwd
awk -F: '{if ($1=="root") {printf "%-15s: %s\n", $1,"Admin"} else {printf "%-15s: %s\n", $1, "Common User"}}' /etc/passwd
awk -F: '{if($NF ~"bash") {printf "%-10s%s\n",$1,"admin"} else {printf "%-10s%s",$1,"commo\n"}}' /etc/passwd
awk -F: -v sum=0 '{if ($3>=500) sum++}END{print sum}' /etc/passwd
~~~
### while
對字段進行循環時使用,比如,判斷字段長度大于4的給予顯示
~~~
while (condition){statement1; statment2; ...}
~~~
~~~
awk -F: '{i=1;while (i<=3) {print $i;i++}}' /etc/passwd
awk -F: '{i=1;while (i<=NF) { if (length($i)>=4) {print $i}; i++ }}' /etc/passwd
~~~
### do-while
~~~
do {statement1, statement2, ...} while (condition)
~~~
~~~
awk -F: '{i=1;do {print $i;i++}while(i<=3)}' /etc/passwd
~~~
### for
~~~
for ( variable assignment; condition; iteration process) { statement1, statement2, ...}
~~~
~~~
awk -F: '{for(i=1;i<=3;i++) print $i}' /etc/passwd
awk -F: '{for(i=1;i<=NF;i++) { if (length($i)>=4) {print $i}}}' /etc/passwd
~~~
for循環還可以用來遍歷數組元素
~~~
for (i in array) {statement1, statement2, ...}
~~~
### case
語法:switch (expression) { case VALUE or /REGEXP/: statement1, statement2,... default: statement1, ...}
### break 和 continue
常用于循環或case語句中
### next
提前結束對本行文本的處理,并接著處理下一行;例如,下面的命令將顯示其ID號為奇數的用戶:
~~~
# awk -F: '{if($3%2==0) next;print $1,$3}' /etc/passwd
~~~
### awk中使用數組
array[index-expression]
要遍歷數組中的每一個元素,需要使用如下的特殊結構:
for (var in array) { statement1, ... }
其中,var用于引用數組下標,而不是元素值;
例子
~~~
# awk -F: '$NF~/[^[:space:]]/{shell[$NF]++}END{for(A in shell){print A,shell[A]}}' /etc/passwd
/bin/sync 1
/bin/bash 2
/sbin/nologin 33
/sbin/halt 1
/sbin/shutdown 1
~~~
~~~
netstat -ant | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
每出現一被/^tcp/模式匹配到的行,數組S[$NF]就加1,NF為當前匹配到的行的最后一個字段,此處用其值做為數組S的元素索引;
awk '{counts[$1]++} END {for(ip in counts) print counts[ip], ip}' /var/log/httpd/access_log
用法與上一個例子相同,用于統計某日志文件中IP地的訪問量
~~~
### awk的內置函數
split(string, array [, fieldsep [, seps ] ])
功能:將string表示的字符串以fieldsep為分隔符進行分隔,并將分隔后的結果保存至array為名的數組中;數組下標為從0開始的序列;
~~~
netstat -ant | awk '/:80\>/{split($5,clients,":");IP[clients[1]]++}END{for(i in IP){print IP[i],i}}' | sort -rn | head -50
~~~
length([string])
功能:返回string字符串中字符的個數;
substr(string, start [, length])
功能:取string字符串中的子串,從start開始,取length個;start從1開始計數;
system(command)
功能:執行系統command并將結果返回至awk命令
systime()
功能:取系統當前時間
tolower(s)
功能:將s中的所有字母轉為小寫
toupper(s)
功能:將s中的所有字母轉為大寫
## 常用例子
### 一、文本間隔
1、在每一行后面增加一空行
~~~
sed G guo.sh
awk '{printf("%s\n\n",$0 ) }'
awk '{print $0, "\n"}'
~~~
2、將文件中原來的空行刪掉,并在在每一行后邊增加一空行
~~~
sed '/^$/d;G '
awk '!/^$/ {printf("%s\n\n",$0 ) }'
~~~
3、在匹配式樣的行前插入一空行
~~~
sed '/good/i\\'
sed '/hello/{x;p;x;}'
awk '{ if(/hello/) printf("\n\%s\n",$0);else print $0}'
~~~
4、在匹配式樣的行后插入一空行
~~~
sed '/good/a\\'
sed '/hello/G'
awk '{if(/hello/) printf("%s\n\n",$0) ;else print $0}'
~~~
5、在匹配式樣的行前、行后各插入一空行
~~~
sed '/hello/{x;p;x;G;}'
awk '{ if(/hello/) printf("\n\%s\n\n",$0);else print $0}'
~~~
### 二、文本的替換
1、在每一行查找到good,然后把good替換為bad
~~~
sed 's/good/bad/'只把每行的第一個good替換為bad
sed 's/good/bad/2'只把每行的第二個good替換為bad
sed 's/good/bad/g'把每一行的所有good替換為bad
sed 's/.?good/\1bad/'只把每一行的的最后一個good替換位bad
sed 's/.?good.?good/\1bad\2/'只把每一行的的倒數第二個good替換位bad
~~~
~~~
awk '{sub(/good/,"bad"); print $0}'只把每行的第一個good替換為bad
awk '{gsub(/good/,"bad"); print $0}'把每一行的所有good替換為bad
sed 's/root/good/p' test
awk '{gsub(/root/,"good");print $0}' test
awk '{gsub(/root/,"god");print $0}' test
~~~
2、只在出現字符串fell字符串的前提下,將找到的行中的good替換為bad
~~~
sed '/fell/ s/good/bad/g'
awk '{if(/fell/) gsub(/good/,"bad"); print $0 }'
~~~
3、只在不出現字符串fell字符串的前提下,將找到的行中的good替換為bad
~~~
sed '/fell/ !s/good/bad/g'
awk '{if(!/fell/) gsub(/good/,"bad"); print $0 }'
~~~
4、多單詞替換,替換為一個單詞
~~~
sed 's/good/bad/g;s/fell/bad/g;s/sun/bad/g'
sed 's/good\|fell\|sun/bad/g'
awk '{gsub(/good|fell|sun/,"bad") ; print $0}'
~~~
5、倒置所有行,第一行變為最后一行(模擬tac)
~~~
sed '1!G;h;$!d'
sed -n '1!G;h;$p'
awk '{A[i++]=$0} END{for (j=i-1;j>=0;j--) print A[j]}'
~~~
6、將每兩行連接為一行
~~~
sed '$!N;s/\n/ /'
awk '{f=!f;if(!f) printf("%s",$0);else printf("%s\n",$0)}'
~~~
7、在文件中每隔5行顯示一空行
~~~
sed '0~5G'
sed 'n;n;n;n;G'
awk '{print $0 ;i++;if(i==5) {printf( "\n") ;i=0}}'
~~~
#### 三、選擇性的顯示特定行
1、顯示文件的前10行
~~~
sed 10q
awk '{print ;if(NR==10) exit }'
~~~
2、顯示文件的第一行
~~~
sed q
awk '{ print;exit}'
~~~
如何用sed打印文件范圍從第二行至倒數第二行?
sed '1d;$d'
1、求和
~~~
cat data|awk '{sum+=$1} END {print "Sum = ", sum}'
~~~
2、求平均
~~~
cat data|awk '{sum+=$1} END {print "Average = ", sum/NR}'
~~~
3、求最大值
~~~
cat data|awk 'BEGIN {max = 0} {if ($1+0 > max+0) max=$1 fi} END {print "Max=", max}'
~~~
4、求最小值(min的初始值設置一個超大數即可)
~~~
awk 'BEGIN {min = 1999999} {if ($1<min) min=$1 fi} END {print "Min=", min}'
~~~
5、求訪問次數的Top 10 Resource,可以根據此進行優化
~~~
cat output/logs/cookie_logs/`date +%u`/cookie_log|grep -v '172.16'|grep -v '127.0.0.1' |awk -F' ' '{ if(index($1,"219.141.246")!=0) print $2; else print $1 } '|sort|uniq -c|sort -n |tail -n 10
~~~
連接狀態
~~~
netstat -lnta | awk '{stat[$6]++} END {for (i in stat){print i,stat[i]}}'
~~~
查看日志
~~~
awk '{a[$1]+=1} END {for(i in a){print a[i], i}}' log | sort -rn
~~~
- 目錄
- 離散的內容
- IO模型
- 網卡綁定
- ssh
- 硬件測試
- 硬件
- limits
- 網絡流量
- 硬盤IO
- 硬盤
- tmux
- 主機名和域名
- http_proxy
- iptables
- 內核參數
- 塊設備和字符設備
- 內存
- 虛擬內存并非交換分區
- 網絡延時
- 概念
- 多核壓縮
- linux基礎
- SSH協議
- 軟件管理
- yum
- 制作本地源 yum系列
- 制作本地源 apt系列
- apt
- 在 Linux 中移除從源代碼安裝的程序的一種簡單的方法
- 其他
- 源碼編譯和二進制安裝后更改配置
- DNS
- bind
- 守護進程
- 特殊權限
- limit.conf配置
- 網絡
- shell-ok
- 變量ok
- 數組ok
- 系統變量和環境變量
- 運算符和計算-ok
- 條件測試-ok
- 選擇-ok
- shell循環-ok
- 輸出echo和printf-ok
- 技巧-ok
- pre-web
- http協議
- web服務器
- Apache
- apache安裝
- yum安裝
- 二進制安裝
- 編譯安裝
- httpd命令
- 運行 監控apache
- apache配置文件
- 常用配置
- MPM多處理模塊
- 編譯模塊
- apache模塊
- apache核心模塊
- apache標準模塊
- apache第三方模塊
- 虛擬主機
- 1
- CGI-FastCGI-SSI
- 別名和重定向
- apache應用
- 301重定向
- apache防盜鏈
- http轉化為https
- 訪問時間段控制
- 控制訪問目錄
- 限制指定USER_AGENT
- 不同客戶端訪問不同網頁
- apache黑名單
- httpd之禁止解析php
- 不記錄css/js/img的訪問日志
- 瀏覽器端靜態緩存
- apache訪問日志自動切割
- order-require
- 壓縮傳輸
- httpd-ssl
- apache代理
- 正向代理
- 反向代理
- apache調優
- httpd壓力測試工具ab
- CGI測試
- php
- php原理
- httpd和php的結合方式
- php yum安裝之DSO模式
- php 編譯安裝之DSO模式
- php-fpm詳解
- php yum安裝之php-fpm模式
- php 編譯安裝之FastCGI模式
- php擴展之mysql
- php擴展之gd
- php擴展之pcntl
- php擴展之xcache
- php擴展之ZendGuardLoader
- phpMyAdmin
- wordpress
- 數據庫-mysql
- 數據庫原理
- mysql數據庫原理
- mysql源碼編譯安裝
- mysql二進制包安裝
- mysql命令行工具
- 更改密碼
- 數據庫授權grant
- mysql日志
- 命令
- 常用
- 小命令大作為
- awk 報告生成器
- 網絡命令
- 命令查找
- 壓縮歸檔命令
- 文件管理
- 文件管理命令
- 文件查看命令
- 目錄管理命令
- 用戶管理命令
- 用戶權限管理
- curl
- cheat
- chrony
- command
- crontab任務計劃
- cut
- date
- dd
- df
- echo
- find
- grep
- hash
- iftop
- kill pkill killall
- ls
- lsmod和modprobe
- lsof
- man
- mkpasswd
- mount
- mtr
- netstat
- nmap
- nc
- NTP
- passwd
- rm
- rdate
- pv
- sar系統活動情況報告
- sed文本處理命令
- setup
- screen
- shutdown
- sort 命令
- sudo
- tcpdump
- top
- uniq
- wget
- who
- xargs
- 監控
- zabbix郵件報警
- Redis
- redis安裝
- redis數據類型和操作方法
- redis持久化和配置
- redis主從配置
- php連接redis
- redis實現session共享
- 安裝測試
- redis設置密碼
- ELK日志分析系統
- elasticsearch
- logstash
- logstash插件
- filebeat日志收集
- kibana
- jenkins
- jenkins安裝與配置
- 案例1
- 案例2
- 案例3
- 代碼倉庫之svn
- svn服務端配置
- 常用操作
- svn備份
- LB集群
- LVS負載均衡集群
- ipvsadm使用方法
- LVS調度方法
- NAT原理
- NAT實踐
- DR原理
- DR實踐
- TUN原理
- LVS持久連接
- HA集群
- HPC集群
- 共享存儲
- ftp協議
- vsftpd
- NFS
- 網站架構發展
- 文件同步
- rsync基本用法
- rsync安裝和使用_拉取模式
- lsyncd安裝和用法
- zabbix
- zabbix服務端安裝
- zabbix客戶端安裝
- zabbix編譯安裝
- zabbix監控tomcat
- zabbix監控mysql
- gitlab
- supervisor
- nsq
- ruby
- nodejs
- consul
- mesos
- zookeeper
- rwho
- 對象存儲
- 工具
- rclone
- minio
- linux 性能調優
- CPU
- 第一部分 CPU
- 安全