awk介紹
- awk:Aho, Weinberger, Kernighan,報告生成器,格式化文本輸出
- 有多種版本:New awk(nawk),GNU awk( gawk)
- gawk:模式掃描和處理語言
- 基本用法:
awk [options] ‘program’ var=value file…
awk [options] -f programfile var=value file…
awk [options] ?‘BEGIN{ action;… } pattern{ action;… } END{ action;… }’ ?file …
awk 程序通常由:BEGIN語句塊、能夠使用模式匹配的通用語句塊 、END語句塊,共3部分組成
program通常是被單引號或雙引號中
- 選項:
-F 指明輸入時用到的字段分隔符
-v var=value: 自定義變量
awk不能修改文件,只做輸出顯示處理
[root@localhost ~]# which awk
/usr/bin/awk
[root@localhost ~]# ll /usr/bin/awk
lrwxrwxrwx. 1 root root 4 Dec 14 21:53 /usr/bin/awk -> gawk
awk語言
- 基本格式:awk [options] ‘program’ file…
- program:pattern{action statements;..}
- pattern和action:
pattern部分決定動作語句何時觸發及觸發事件
BEGIN,END
pattern決定了是針對那種類型的行進行處理。雖然默認把每一行都讀進來,但是讀進來的行要不要處理,可以定義pattern進行過濾,例如:如果滿足pattern就執行動作,不滿足就不符合條件,就可以直接跳到下一行開始。
action statements對數據進行處理,放在{}內指明。打印顯示必要的內容
print, printf
print:簡單的把必要的內容數據顯示出來
printf:更加具體詳細的定義顯示的格式,例如添加控制符,打印的時候字段和字段之間有多寬、小數點有多少位
- 分割符、域和記錄
awk執行時,由分隔符分隔的字段(域)標記,分割成若干個列,每個列系統會自動分配變量$1,$2..$n對應的表示他們,用$1,$2..$n分別表示這一行的第幾列,稱為域標識。$0為所有域,注意:和shell中變量$符含義不同
文件的每一行稱為記錄(默認回車換行分割記錄)
省略action,則默認執行 print $0 的操作,打印一整行
$0為所有域,整行的所有字段
在bash中$0 表示程序本身
printf也是一個內部命令,作用和echo相似,按照一定格式顯示字符串
[root@localhost ~]# type printf
printf is a shell builtin
[root@localhost ~]# man printf
NAME
printf – format and print data 格式化和打印數據
記錄不一定非得是一行才成為一條記錄,例如:別的形式
[root@localhost ~]# vim file
a:bb;ccc:ddd;
例如該文件中,可以認為“:”分開的為字段,“;”分開的為記錄(一行),不是按照回車換行為記錄的分隔符,默認記錄的分割符是回車換行,也可以是別的字符
awk工作原理
- 第一步:執行BEGIN{action;… }語句塊中的語句
- 第二步:從文件或標準輸入(stdin)讀取一行,然后執行pattern{ action;… }語句塊,它逐行掃描文件,從第一行到最后一行重復這個過程,直到文件全部被讀取完畢。
從命令的執行結果來的數據去讀取第一行,然后去執行pattern中的action,看是否符合pattern定義,如果符合pattern定義就執行里面的action,不符合就不處理,讀取下一行,知道文件處理完
- 第三步:當讀至輸入流末尾時,執行END{action;…}語句塊
- BEGIN語句塊在awk開始從輸入流中讀取行之前被執行,這是一個 可選的語句塊,比如變量初始化、打印輸出表格的表頭等語句通常 可以寫在BEGIN語句塊中
- END語句塊在awk從輸入流中讀取完所有的行之后即被執行,比如 打印所有行的分析結果這類信息匯總都是在END語句塊中完成,它也是一個可選語句塊
- pattern語句塊中的通用命令是最重要的部分,也是可選的。如果 沒有提供pattern語句塊,則默認執行{ print },即打印每一個讀取 到的行,awk讀取的每一行都會執行該語句塊
awk
- print格式: print item1, item2, … item1表示要打印的字符,可以是普通字符串,也可以是要打印的列
- 要點:
(1) 逗號分隔符
(2) 輸出的各item可以字符串,也可以是數值;當前記錄的字段、 變量或awk的表達式
(3) 如省略item,相當于print $0
- 示例:
awk ‘{print “hello,awk”}’
awk –F: ?‘{print}’ ?/etc/passwd
awk –F: ??‘{print “wang”}’ ??/etc/passwd
awk –F: ‘{print $1}’ ??/etc/passwd awk –F: ‘{print $0}’ ?/etc/passwd
awk –F: ‘{print $1”\t”$3}’ ?/etc/passwd tail –3 ?/etc/fstab |awk ‘{print $2,$4}’
例子:
如果pattern忽略不寫,就會處理所有行
每讀一行顯示一行,讀進來一看,pattern未定義,符合條件,符合條件就打印
[root@localhost /app]# awk ‘{print “hello”}’ /etc/issue
hello
hello
從標準輸入讀取輸入進行打印
[root@localhost /app]# awk ‘{print “hello”}’
a
hello
b
hello
awk可以讀取標準輸入
[root@localhost /app]# cat /etc/issue | awk ‘{print “hello”}’
hello
hello
hello
管道把前一個命令的標準輸出作為后一個命令的標準輸入
[root@localhost /app]# awk ‘{print “hello\nclass27″}’ /etc/centos-release
hello
class27
做數字運算,只要是字符串,就需要加引號引起來,數字不需要加引號
[root@localhost /app]# awk ‘{print 2*3}’ /etc/centos-release
6
[root@localhost /app]# awk ‘{print 2^3}’ /etc/centos-release
8
[root@localhost /app]# awk ‘{print 2/3}’ /etc/centos-release
0.666667
希望取出特定的字段,awk默認的分隔符是空格
[root@localhost /app]# awk -F “:” ‘{print $1,$3,$7}’ passwd
取分區的利用率
[root@localhost /app]# df | grep /dev/sd | awk ‘{print $5}’
8%
1%
4%
[root@localhost /app]# df | grep /dev/sd | awk ‘{print $1,$5}’
/dev/sda2 8%
/dev/sda3 1%
/dev/sda1 4%
{print $1,$5},$1 和 $5 之間使用“,”,輸出時字段的分割符為空格,也可以進行指定,例如:
[root@localhost /app]# df | grep /dev/sd | awk ‘{print $1″——“$5}’
/dev/sda2——8%
/dev/sda3——1%
/dev/sda1——4%
[root@localhost /app]# df | grep /dev/sd | awk ‘{print $1”\t“$5}’
/dev/sda2 8%
/dev/sda3 1%
/dev/sda1 4%
[root@localhost /app]# df | grep /dev/sd | awk ‘{print $1”\n“$5}’
/dev/sda2
8%
/dev/sda3
1%
/dev/sda1
4%
$0打印整行內容
默認不寫也是打印整行內容
[root@localhost ~]# df | grep ‘dev/sd’ | awk ‘{ print }’
/dev/sda2 ??????52403200 16332416 ?36070784 ?32% /
/dev/sda5 ??????20961280 ???51048 ?20910232 ??1% /app
/dev/sda1 ???????1038336 ??227464 ???810872 ?22% /boot
[root@localhost ~]# df | grep ‘dev/sd’ | awk ‘{ print $0 }’
/dev/sda2 ??????52403200 16332416 ?36070784 ?32% /
/dev/sda5 ??????20961280 ???51048 ?20910232 ??1% /app
/dev/sda1 ???????1038336 ??227464 ???810872 ?22% /boot
awk變量
- 變量:內置和自定義變量
- FS:輸入字段分隔符,默認為空白字符
awk -v?FS=’:’ ?‘{print $1,FS,$3}’ /etc/passwd
awk ?–F: ??‘{print $1,$3,$7}’ /etc/passwd
awk -v?FS=’:’?等價于 awk -F ‘:’
FS:field,稱為域、字段、列column、屬性
行,稱為記錄,record
- OFS:輸出字段分隔符,默認為空白字符
awk ?-v FS=‘:’ ?-v OFS=‘:’ ‘{print $1,$3,$7}’ /etc/passwd
- RS:輸入記錄分隔符,指定輸入時的換行符
awk -v RS=’ ‘ ‘{print }’ /etc/passwd
- ORS:輸出記錄分隔符,輸出時用指定符號代替換行符
awk -v RS=’ ‘ -v ORS=’###’‘{print }’ /etc/passwd
- NF:字段數量
awk ?-F: ‘{print NF}’ /etc/fstab,引用內置變量不用$
awk ?-F: ?‘{print $(NF-1)}’ ?/etc/passwd
- NR:記錄號
awk ‘{print NR}’ ?/etc/fstab ; awk END'{print NR}’ ?/etc/fstab
-v表示給變量賦值,FS是awk自帶的變量,字段的分隔符,指定文件輸入的分隔符是什么
[root@localhost /app]# awk -F ‘:’ ‘{print $1,$3}’ passwd
[root@localhost /app]# awk -v FS=’:’?‘{print $1,$3}’ passwd
變量的好處是可以在awk中輸出時使用
[root@localhost /app]# awk -v FS=’:’ ‘{print $1,FS,$3}’ passwd
root : 0
bin : 1
awk還可以使用bash變量,例如調用bash中的變量
[root@localhost /app]# sep=”:”;awk -v FS=”$sep” ‘{print $1,FS,$3}’ passwd
root : 0
bin : 1
-F只能在外面使用bash中的變量,但是里面就無法使用了
[root@localhost ~]# sep=”:”;awk -F “$sep” ‘{print $1,”:”$3}’ passwd
root :0
bin :1
輸出分隔符
[root@localhost /app]# awk -v FS=’:’?-v OFS=’+’?‘{print $1,$3}’ passwd
root+0
bin+1
輸入分割符決定字段之間怎么分割進行處理
輸出分隔符決定字段之間怎么輸出進行顯示
把一個文件讀進來怎么知道怎樣算是一條記錄?默認回車換行是一條記錄
例如:認為一條記錄的分割符為‘;’,字段的分隔符默認為空白符
[root@localhost /app]# cat file
aa bb?cc;ee
ff?oo;xx
yy?zz
[root@localhost /app]# awk -v RS=”;”?‘{print $2}’ file
bb
ff
yy
[root@localhost /app]# cat file
a
b
c?aa
bb
cc?aaa
bb
ccc?aaa
以空格作為行的分隔符
[root@localhost /app]# awk -v RS=” ” ‘{ print $1,$2}’ file
a b
aa bb
aaa bb
aaa
以空格作為行的分隔符,所以abc算是一條記錄,默認字段的分割符為空白符,回車換行也是空白符,所以a是$1,b是$2,c是$3,所以第一行為a b
所以,記錄分別是:
a b c
aa bb cc
aaa bb ccc
aaa
輸出的時候一條一條的記錄默認是換行分割出來的,輸出的時候,記錄和記錄之間到的默認分割符是回車換行
指定輸出的分隔符
[root@localhost ~]# cat f2.txt
a b
aa bb
aaa bb
aaa
指定輸出記錄的分隔符
[root@localhost ~]# awk -v RS=” ” -v ORS=”—“?‘{print $1,$2}’ f2.txt
a —b aa—bb aaa—bb aaa—
字段數量NF
顯示每個行有多少個字段
[root@localhost ~]# awk -F: ‘{print NF}’ /etc/passwd
7
輸出最后一個字段
[root@localhost ~]# awk -F: ‘{print $NF}’ /etc/passwd
/bin/bash
輸出倒數第二個字段
[root@localhost ~]# awk -F: ‘{print $(NF-1)}’ /etc/passwd
/root
取出遠程連接IP
[root@localhost ~]# ss -nt | awk ‘{print $NF}’ | awk -F: ‘{print $1}’
Address
172.18.101.66
取出分區利用率
[root@localhost ~]# df | grep ‘/dev/sd’ | awk ‘{print $(NF-1)}’|awk -F% ‘{print $1}’
32
1
22
取http訪問日志
[root@localhost /app]# awk ‘{print $1}’ /var/log/httpd/access_log
172.18.101.66
NR:記錄號,每條記錄的編號
[root@localhost /app]# awk ‘{print NR,$0}’ /etc/passwd
1 root:x:0:0:root:/root:/bin/bash
空行也算行號
[root@localhost /app]# awk ‘{print NR,$0}’ /etc/fstab
1
2 #
3 # /etc/fstab
同時處理多個文件
[root@localhost /app]# awk ‘{print NR,$0}’ /etc/fstab /etc/issue
在第一個文件輸出完之后接著輸出第二個文件的內容
同時處理多個文件,每個文件獨立編號
[root@localhost /app]# awk ‘{print FNR,$0}’ /etc/fstab /etc/issue
1
2 #
3 # /etc/fstab
1 \S
2 Kernel \r on an \m
3
顯示文件名
[root@localhost /app]# awk ‘{print FNR,FILENAME,$0}’ /etc/fstab /etc/issue
1 /etc/fstab
2 /etc/fstab #
3 /etc/fstab # /etc/fstab
1 /etc/issue \S
2 /etc/issue Kernel \r on an \m
3 /etc/issue
awk
- FNR:各文件分別計數,記錄號
awk ‘{print FNR}’ ?/etc/fstab /etc/inittab
- FILENAME:當前文件名
awk ‘{print FILENAME}’ ?/etc/fstab
- ARGC:命令行參數的個數
awk ‘{print ARGC}’ ?/etc/fstab /etc/inittab
awk ‘BEGIN {print ARGC}’ ?/etc/fstab /etc/inittab
- ARGV:數組,保存的是命令行所給定的各參數
awk ‘BEGIN {print ARGV[0]}’ ?/etc/fstab /etc/inittab
awk ‘BEGIN {print ARGV[1]}’ ?/etc/fstab /etc/inittab
命令行參數的個數
[root@localhost ~]# awk ‘{print ARGC}’ /etc/fstab /etc/issue
3
[root@localhost /app]# awk ‘{print ARGV[0]}’ /etc/fstab /etc/issue
awk
[root@localhost /app]# awk ‘{print ARGV[1]}’ /etc/fstab /etc/issue
/etc/fstab
[root@localhost /app]# awk ‘{print ARGV[2]}’ /etc/fstab /etc/issue
/etc/issue
三個參數從0開始編,認為awk也是參數之一
awk變量
- 自定義變量(區分字符大小寫)
(1) -v var=value
(2) 在program中直接定義
- 示例:
awk -v test=’hello gawk’ ‘{print test}’ /etc/fstab
awk -v test=’hello gawk’ ‘BEGIN{print test}’
awk ‘BEGIN{test=”hello,gawk”;print test}’
awk –F:‘{sex=“male”;print $1,sex,age;age=18}’ /etc/passwd
cat awkscript ?{print script,$1,$2} ?awk -F: -f awkscript script=“awk” /etc/passwd
自定義變量
#?awk -v sep=”:”?-F: ‘{print $1sep$3}’ /etc/passwd
root:0
分別進行定義
# awk -v uid=”uid” -F: ‘{user=”username”;print user”:”$1,uid”:”$3}’ /etc/passwd
username:root uid:0
#?awk -v user=”username”?-v uid=”uid”?-F: ‘{print user”:”$1,uid”:”$3}’ /etc/passwd
username:root uid:0
在program中直接定義
# awk -F: ‘{user=”username”;uid=”uid”; print user”:”$1,uid”:”$3}’ /etc/passwd
username:root uid:0
定義在awk程序里面不能使用bash中的變量,在外部定義可以使用bash中的變量
# u=”user”;?awk -F: -v user=”$u”?‘{uid=”uid”; print user”:”$1,uid”:”$3}’ /etc/passwd
user:root uid:0
先使用后定義會現第一行不生效的問題
# awk -F: ‘{print user”:”$1,uid”:”$3;user=”user”;uid=”userid”}’ /etc/passwd
:root :0
user:bin userid:1
原因:第一行讀取進來進行處理的時候,user和uid還是未定義的狀態,但是到第二行的時候,就已經是定義了的狀態了。這一行定義的變量將會在下一行起作用。為避免出現問題,建議先聲明后使用
把awk的指定放入文件中去
[root@localhost ~]# cat awk.script
{user=”username”;uid=”userid”;print user”:”$1,uid”:”$3}
[root@localhost ~]# awk -F: -f awk.script?/etc/passwd
username:root userid:0
本文來自投稿,不代表Linux運維部落立場,如若轉載,請注明出處:http://www.www58058.com/90685