文本三工具grep sed awk
grep egrep fgrep 文本過濾
sed 行編輯器
模式空間、保持空間
awk 報告生成器,格式化文本輸出
AKW: Aho,Weinberger,Kernighan 這個工具的三個人的作者
1970s出現的-->New AWK ,NAWK
linux上用的是GNU awk 簡稱爲gawk
gwak -pattern scanning and processing language
處理:一次讀取一行文本,根據指明的輸入分隔符切割爲n個組成部分;內
建變量$1...$n 顯示整行片段爲$0
基本用法:gawk [options] 'program' FILE1 [FILE...n]
program: PATTREN{ACTION STATEMENTs}
語句之間用;分隔
選項
-F ""指明字段分隔符
-v var=value :自定義變量
1、print
print item1,item2,...
例如 awk '{print $1,$2}' 以默認空格爲分割字段顯示$1 $2
不寫,的話會連接顯示 $1$2
(1)都號分隔符
(2)輸出的item可以是字符串,數值,當前記錄的子段、變量或awk表達式
字符串連接時 '{print "hello:" $1}' 加入字符 ""裏面的東西不會改變,
因此$1不能在""裏面
(3)省略item,就相當於print $0 打印整行
2、變量
1 內建變量
FS:input filed seperator,默認爲空白字符
OFS:output filed seperator,默認爲空白字符
RS: 輸入時的換行符
ORS:輸出時的換行符
NF:顯示行的字段數
這個時候如果打印$NF 是打印每行字段的最後一個字段
因爲你統計了每行的字段
{print NF} {print NR}
因此打印變量不要加$
NR:統計文件的行數
FNR:每個文件單獨計數行數 {print FNR} file1 file2 ..
FILENAME:當前正在處理的文件名
如果直接打印,是每處理一行就會顯示一次文件名
可以用 'BEGIN{print FILENAME}' 顯示一次
ARGC:命令行參數的個數
ARGV:數組,保存的是命令行中所給定的各參數
例如 awk 'BEGIN{print ARGV[0] ARGV[1] ARGV[2] ARGC}' file1 file2
就會顯示 awk file1 file2 3 三個參數和總計的參數量
例如
eg1: awk -v FS=':' '{print $1}' /etc/passwd
等於awk -F: '{print $1}' /etc/passwd
eg2:定義輸出分隔符
awk -v FS=':' -v OFS=':' '{print $1}' /etc/passwd
輸出也打印爲分割符爲:
eg3 -v RS=' ' 把空白字符全部當做換行符
-v ORS='#' #作爲輸出的換行
2 自定義變量
-v var=value
變量名區分大小寫、引用變量不需要$
如果不對文件做處理,必須'BEGIN{}' 而不是在處理文件過程中,就不用加文件名稱了
3printf 命令
格式化輸出:printf FORMAT, item1 ....
(1)FORMAT必須給出
(2)printf不會自動換行,需要顯式給出\n
(3)FORMAT中需要分別爲後面的每個item指定一個格式化符號
格式符
%c 顯式字符的ASCII碼
%d,%i 顯式爲十進制,整數
%e,%E 顯式爲科學計數法
%f 顯式爲浮點數
%g,%G以科學計數法,浮點形式顯式數值
%s顯式字符串
%u 無符號整數
%% 顯式% 本身
例如 awk -F: '{printf "Username: $s\n",$1}' /etc/passwd
類似C語言版的輸出
awk -F: '{printf "Username: $s, UID:%d\n",$1,$3}' /etc/passwd
修飾符
#[.#]: 第一個#控制顯示的寬度,第二個#控制小數的精度可以不加
%3.1f
awk -F: '{printf "Username: $15s, UID:%8d\n",$1,$3}' /etc/passwd
默認爲右對齊顯示
-爲左對齊
awk -F: '{printf "Username: $-15s, UID:%8d\n",$1,$3}' /etc/passwd
%-15s 左對齊
-左對齊
+顯示數值的符號
4操作符
算數操作符:
x-+\*^%
-x 負值
+x 轉換爲數值
字符串操作符:沒有符號的操作符,字符串連接
賦值操作符
=,+=,-=,*=,%=,^=,\=
++,--
比較操作符
< > >= <= == !=
模式匹配符
~ 是否匹配
!~是否不匹配
邏輯操作符
&& ||
!
函數調用
function_name(argu1,argu2, ...)
條件表達式
selector?if-true-expression:if-false-expression
1?2:3
1對執行2,不對執行3
eg: awk -F: '{$3>=1000?usertype="common":usertype="sys";printf
"%15s:%-s\n",$1,usertype}' /etc/passwd
5 PATTERN
(1) empty:空模式,匹配每一行
(2)/regular expression/ :僅處理能被此處模式匹配到的行(過濾)
eg1: awk '/^UUID/{print $1}' /etc/fstab
僅顯示開頭爲UUID 的行
awk '!/^UUID/{print $1}' /etc/fstab
加!對整個過濾模式取反
正則表達式
(3)relational expression:關係表達式:如果有“真”有“假”;結果爲真才被處理
真:結果爲非0值,非空字符串
eg: awk -F: '$3>=1000{prinf $1,$3}' /etc/passwd
awk -F: '$NF=="/bin/bash"{print $1,$NF}' /etc/passwd
打印最後一個字段爲/bin/bash的行
(4)line ranges:行範圍,
startline,endline (地址定界) /pat1/ /pat2/
注意:不支持直接給出數字的格式
awk -F: '(NR>=2&&NR<=10){print $1}' /etc/passwd
(5)BEGIN/END模式
BEGIN{} 在開始處理文件中的文本之前執行一次
END{}在文本處理完成之後執行一次
6常用的action
(1)表達式Expressions
(2)控制語句
(3)組合語句
(4)輸入語句
(5)輸出語句
7控制語句
if(confition) {statements}
if(confition) {statements} else {statements}
...
...
7.1 if-else
語法: if(conditon) statement [else statement]
awk -F: '{if($3>=1000) print $1,$3}' /etc/passwd
awk -F: '{if($3>=1000) {print $1,$3} else {print $1,$3}}' /etc/passwd
df -h|awk -F[%] '{print $5}' |awk '{print $NF}'
顯示最後一個字段
df -h|awk -F[%] '/^\/dev/{print $5}' |awk '{print $NF}'
\/轉義 以/dev開頭的行
7.2while循環
語法:while(conditon) statement
條件“真”,進入循環;條件“假”,退出循環
使用場景:對一行內的多個字段逐一類似處理時使用;對數組元素逐一處理
awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {print $i,length($i);i++}}' /etc/grub2.cfg
統計字段
awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {if(length($i)>=7){print $i,length($i)};i++}}' /etc/grub2.cfg
統計字段
7.3 do-while循環
do statement while(condition)
至少執行一次循環體
7.4for循環
語法:for(expr1;expr2;expr3) statement
for(variable assignment;condition;iteration process) {for-body}
7.5 switch語句
語法:switch(expression)
switch(expression){
case VALUE1 or /REGEXP/
statement;
case 2
...
default:statement
}
7.6 break continue
break [n]
continue
7.7next
提前結束對本行的處理而直接進入下一行
awk -F: '{if($3%2!=0) next; print $1,$3}' /etc/passwd
8array
關聯數組array[index-expression]
index-expression
(1)可使用任意字符串
(2)如果某數組元素事先不存在,在引用時awk會自動創建此元素,並且初始化爲
“空串”
要判斷數組中是否存在某元素,要使用“index in array”格式進行
weekdays["mon"]="Monday" 引用元素不要加$
要使用雙引號
eg: awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]=Tuesday;print weekdays["mon"]}'
遍歷數組中每個元素
for(var in array) {for-body}
var會遍歷array的每個索引
netstat -tan |awk '/^tcp\>/{state[$NF]++}END{for(i in state) {print i,state[i]}}'
其中 state[$NF]++表示 索引數組的自增
結果爲
Listen 3
Establish 3
用於統計服務很給力
awk '{ip[$1]++}END{for (i in ip) {print i,ip[i]}}' /var/log/httpd/access_log
這就是所謂的報告生成器
例題:
1統計/etc/fstab中每個文件系統類型出現的次數
awk '/^UUID/{fs[$3]++}END{for(i in fs) {print i,fs[i]}}' /etc/fstab
2統計指定文件中每個單詞出現的次數
行內字段遍歷
awk '{for(i=1;i<=NF;i++){count[$i]++}}END{for (i in count) {print i,count[i]}}' /etc/fstab
9函數
9.1內置函數
數值處理
rand() 返回0-1之間一個隨機數
字符串處理
length([s]) 返回指定字符串的長度
sub(r,s,[t]) r表示模式來查找t所表示的字符串中的匹配的內容,並將其第一次出現替換爲s
gsub(r,s,[t]) 全局替換
split(s,a,[r]) 以r爲分隔符切割字符s,並將切割後的結果保存至a所表示的數組中。數組從1標號
例如 netstat -tan |awk '/^tcp\>/{split($5,ip,":");print ip[1]}' 打印每一行的ip
netstat -tan |
awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++}END{for (i in count) {print i,count[i]}}'
統計ip次數
9.2自定義函數