awk學習(一)

awk介紹

  • awk:Aho, Weinberger, Kernighan,報告生成器,格式化文本輸出
  • 有多種版本:New awk(nawk),GNU awk( gawk),一般我們用的就是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必須被單引號括住

工作原理

類似sed,也會向內存申請一塊空間,每次讀取文件一行,按照分隔符切割成字段——列,對於這些列,awk有專門的名稱表示: $0——整行; $1 ——第一列;$2 $3 ;然後根據需要打印特定的列(默認有一個自動打印所有列的功能)

第一步:執行BEGIN{action;… }語句塊中的語句
第二步:從文件或標準輸入(stdin)讀取一行,然後執行pattern{ action;… }語句塊,它逐行掃描文件,從第一行到最後一行重複這個過程,直到文件全部被讀取完畢。
第三步:當讀至輸入流末尾時,執行END{action;…}語句塊
 BEGIN語句塊在awk開始從輸入流中讀取行之前被執行,這是一個可選的語句塊,比如變量初始化、打印輸出表格的表頭等語句通常可以寫在BEGIN語句塊中

 END語句塊在awk從輸入流中讀取完所有的行之後即被執行,比如打印所有行的分析結果這類信息彙總都是在END語句塊中完成,它也是一個可選語句塊

 pattern語句塊中的通用命令是最重要的部分,也是可選的。如果沒有提供pattern語句塊,則默認執行{ print },即打印每一個讀取到的行,awk讀取的每一行都會執行該語句塊

選項

默認分隔符爲空格;

  • -f:將程序放入文本中,-f調用
  • -F:指定分隔符
  • -v var=value:自定義變量

分隔符、域和記錄

• awk執行時,由分隔符分隔的字段(域)標記$1,$2..$n稱爲域標識。$0爲所有域,
注意:和shell中變量$符含義不同
• 文件的每一行稱爲記錄
• 省略action,則默認執行 print $0 的操作

基本格式

awk [options] 'program' file
program由兩部分組成:模式+動作

pattern:表示模式,根據pattern條件,過濾匹配的行進行處理,不寫則匹配每一行;

action:動作,常用於打印

BEGIN——表示在處理文件之前執行的語句;

END———表示在處理完文件之後執行的語句,如彙總

print

print格式: print item1, item2, ...
要點:
(1) 逗號分隔符
(2) 輸出的各item可以字符串,也可以是數值;當前記錄的字段、變量或awk的表達式
(3) 如省略item,相當於print $0

示例:

> 取分區的第一列和第三列
[root@centos7 ~ ]#df|awk '{print $1,$3}'
Filesystem Used
/dev/sda2 4275140
devtmpfs 0
tmpfs 0
tmpfs 10312
tmpfs 0
/dev/sda3 33112
/dev/sda1 157932
tmpfs 32
/dev/sr0 9176232

> 打印固定字符符,默認awk接收標準輸入
[root@centos7 ~ ]#awk '{print "hello,awk"}'
xin
hello,awk
haha
hello,awk
wang
hello,awk
lhy
hello,awk
^C
[root@centos7 ~ ]#

> 多個字段用tab分割,分割符需要用雙引號引起來,否則報錯
[root@centos7 ~ ]#awk -F: '{print $1"\t"$2}' /etc/passwd
root    x
bin x
daemon  x
adm x
lp  x
sync    x
shutdown    x
halt    x

> 取分區利用率:
[root@centos7 ~ ]#df|grep "^/dev/sd"|awk '{print $1"\t"$5}'|awk -F% '{print $1}'
/dev/sda2   9
/dev/sda3   1
/dev/sda1   16
後面還有更加簡單的方法,不信,那就接着往下看

awk變量

變量賦值必須加-v

awk變量分爲內置變量和自定義變量

內置變量

FS:輸入字段分割符,即讀取的文件中列與列之間的分隔符,爲未處理之前,默認爲空格;

[root@centos7 ~ ]#awk -v FS=: '{print $1,$3}' /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6

> 好處:可以在{}中引用
[root@centos7 ~ ]#awk -v FS=: '{print $1FS$3}' /etc/passwd
root:0
bin:1
daemon:2
adm:3

> 並且支持shell變量
[root@centos7 ~ ]#set=:
[root@centos7 ~ ]#echo $set
:
[root@centos7 ~ ]#awk -v FS=$set '{print $1FS$3}' /etc/passwd
root:0
bin:1
daemon:2
adm:3
lp:4

OFS:輸出字段分隔符,爲處理之後的分隔符,默認爲空格;

> 指定輸出字段分割符爲----,建議對分隔符的值用引號引起來
[root@centos7 ~ ]#awk -v FS=":"  -v OFS="----" '{print $1,$3}' /etc/passwd
root----0
bin----1
daemon----2
adm----3
lp----4

RS:輸入記錄分隔符,即行與行之間的分隔符,默認爲換行符;

> 準備環境:“;”行的分隔符,","爲列的分隔符;
[root@centos7 data ]#cat f1
a,b,c;1,2,3,4;A,B,C
aa,bb,cc,dd

> 打印每一行的第3列和第4列 
[root@centos7 data ]#awk -v FS="," -v RS=";" '{print $3,$4}' f1
c 
3 4
C
aa bb
雖然C和aa換行了,但是以逗號爲分隔符,所以輸出的字段Caa爲一列,不過保留換行;

ORS:輸出記錄分隔符,默認爲換行符

[root@centos7 data ]#cat f1
a,b,c;1,2,3,4;A,B,C
aa,bb,cc,dd

> 指定輸出的列的分隔符爲--,輸出的行的分隔符爲+++
[root@centos7 data ]#awk -v FS="," -v OFS="--" -v RS=";" -v ORS="+++" '{print $3,$4}' f1
c--+++3--4+++C
aa--bb+++[root@centos7 data ]#
可以看到Caa是在一行的,並且是一列;

NF:字段數量

> 打印/etc/passwd中每一行的字段數量
[root@centos7 data ]#awk -F: '{print NF}' /etc/passwd
7
7
7
7
7

> 打印最後一個字段
[root@centos7 data ]#awk -F: '{print $7}' /etc/passwd
/bin/bash
/sbin/nologin
/sbin/nologin>
/sbin/nologin

> 通過NF打印最後一個字段
[root@centos7 data ]#awk -F: '{print $NF}' /etc/passwd
/bin/bash
/sbin/

> 打印倒數第三個字段
[root@centos7 data ]#awk -F: '{print $NF-2}' /etc/passwd
-2
-2
-2
-2
> 注意:要加(),否則會出現上面的情況
[root@centos7 data ]#awk -F: '{print $(NF-2)}' /etc/passwd
root
bin
daemon
adm

NR: 記錄號,第幾條記錄,說白了就是行號

[root@centos7 data ]#awk  -F: '{print NR,$1}' /etc/passwd
1 root
2 bin
3 daemon
4 adm
5 lp
6 sync

注意:NR後面跟多個文件時,會合並統一計數

Markdown

FNR:各文件分別計數,記錄號

Markdown

FILENAME:當前文件名

[root@centos7 data ]#awk -F: '{print FNR,FILENAME,$1}' /etc/passwd /etc/issue
1 /etc/passwd root
2 /etc/passwd bin
3 /etc/passwd daemon
4 /etc/passwd adm
5 /etc/passwd lp
6 /etc/passwd sync
7 /etc/passwd shutdown
8 /etc/passwd halt
9 /etc/passwd mail

ARGC:命令行參數的個數

[root@centos7 data ]#awk -F: '{print ARGC}' /etc/passwd /etc/issue
3
3
3
3
3
> 怎麼樣,有沒有很奇怪,不應該是兩個參數嗎? 看下面

ARGV:數組,保存命令行各個參數Markdown

自定義變量

  • -v var=value
  • 在program中直接定義

示例:

[root@centos7 data ]#awk -F: -v USER="username" -v UID="userid" -v ORS="\n-------\n" '{print USER":"$1"\n"UID":"$3}' /etc/passwd
username:root
userid:0
-------
username:bin
userid:1
-------
username:daemon
userid:2
-------

[root@centos7 data ]#awk -F: '{USER="username";UID="userid";print USER":"$1"\n"UID":"$3}'  /etc/passwd 
username:root
userid:0
username:bin
userid:1
username:daemon
userid:2
username:adm

變量必須先定義,再使用;

-f的用法————調用文件中的program

[root@centos7 data ]#cat awk.txt 
{USER="username";UID="userid";print USER":"$1"\n"UID":"$3}  
[root@centos7 data ]#awk -F: -f awk.txt /etc/passwd
username:root
userid:0
username:bin
userid:1

printf命令

格式化輸出;

語法:

printf “FORMAT”, item1, item2, 
  • 必須指定FORMAT
  • 不會自動換行,需要顯式給出換行控制符,\n
  • FORMAT中需要分別爲後面每個item指定格式符

  • 格式化符,常用的是%s和%d

    格式符:與item一一對應
    %c: 顯示字符的ASCII碼
    %d, %i: 顯示十進制整數
    %e, %E:顯示科學計數法數值
    %f:顯示爲浮點數
    %g, %G:以科學計數法或浮點形式顯示數值
    %s:顯示字符串
    %u:無符號整數
    %%: 顯示%自身
  • 修飾符,

    #[.#]:第一個數字控制顯示的寬度;第二個#表示小數點後精度,%3.1f
    -: 左對齊(默認右對齊) %-15s
    +:顯示數值的正負符號 %+d

示例:

awk -F: ‘{printf "%s",$1}’ /etc/passwd
awk -F: ‘{printf "%s\n",$1}’ /etc/passwd
awk -F: '{printf "%-20s %10d\n",$1,$3}' /etc/passwd
awk -F: ‘{printf "Username: %s\n",$1}’ /etc/passwd
awk -F: ‘{printf “Username: %s,UID:%d\n",$1,$3}’ /etc/passwd
awk -F: ‘{printf "Username: %15s,UID:%d\n",$1,$3}’ /etc/passwd
awk -F: ‘{printf "Username: %-15s,UID:%d\n",$1,$3}’ /etc/passwd

Markdown

Markdown

Markdown

Markdown

-F指定多分隔符

Markdown

面試題

實驗環境:
[root@centos7 data ]#cat host.txt 
1 blog.xin.com
2 www.wang.com
3 good.xin.com
999 study.wang.com

實驗要求:取出每一行中的主機名,如blog、www等,然後追加到該文本中。

步驟:
[root@centos7 data ]#awk -F"[ .]" '{print $2}' host.txt >> host.txt 
[root@centos7 data ]#cat host.txt 
1 blog.xin.com
2 www.wang.com
3 good.xin.com
999 study.wang.com
blog
www
good
study

操作符

算術操作符

x+y, x-y, x*y, x/y, x^y, x%y
-x: 轉換爲負數
+x: 轉換爲數值

字符串操作符

沒有符號的操作符,字符串連接

賦值操作符

=, +=, -=, *=, /=, %=, ^=
++, --

注意點:i++和++i的區別
++i和i++雖然都會對i進行+1賦值給i,但是順序是不一樣的:
i++是先使用i,再去進行+運算;
++i是先運算,再去使用i;

比較操作符

==, !=, >, >=, <, <=

示例:
[root@centos7 data ]#awk -F: '$3==0{print $1}' /etc/passwd
root
[root@centos7 data ]#awk -F: '$3!=0{print $1}' /etc/passwd
bin
daemon
adm
......
[root@centos7 data ]#awk -F: '$3>=1000{print $1}' /etc/passwd
nfsnobody
xin
lhy

模式匹配符

~:左邊是否包含右邊的字符
!~:不包含

示例:
> $0即整行,是否包含root字符的行
[root@centos7 data ]#awk -F: '$0 ~ /root/{print $1}' /etc/passwd
root
operator
> 雖然使用雙引號也可以,但是不建議,有些時候會報錯,並且//之間支持正則表達式
[root@centos7 data ]#awk -F: '$0 ~ "root"{print $1}' /etc/passwd
root
operator

> $0中以root開頭的行
[root@centos7 data ]#awk -F: '$0 ~ /^root/{print $1}' /etc/passwd
root
> 不以root開頭的行,取反
[root@centos7 data ]#awk -F: '$0 !~ /^root/{print $1}' /etc/passwd
bin
daemon
adm
......

注意:模式匹配符可以不用,因爲awk默認直接可以匹配正則,詳情往先看

邏輯操作符

邏輯操作符:與&&,或||,非!

示例:
• awk –F: '$3>=0 && $3<=1000 {print $1}' /etc/passwd
• awk -F: '$3==0 || $3>=1000 {print $1}' /etc/passwd
• awk -F: ‘!($3==0) {print $1}' /etc/passwd
• awk -F: ‘!($3>=500) {print $3}’ /etc/passwd

注意:取反要加小括號,否則報錯

條件表達式(三目表達式):

selector?if-true-expression:if-false-expression

即:A? B:C
A爲條件,B和C是動作;如果A爲真,則執行B;否則執行C;
注意B和C之間的分隔符爲:

示例:
awk -F: '{$3>=1000?usertype="Common User":usertype="Sysadmin or SysUser";printf
"%15s:%-s\n",$1,usertype}' /etc/passwd

awk PATTERN

直接支持正則,不需要$0 ~等額外的字符

  • 如果未指定:空模式,匹配每一行

  • /regular expression/:僅處理能夠模式匹配到的行,需要用/ /括起來

如:awk '/^UUID/{print $1}' /etc/fstab

  • print省略後,打印整行
> 過濾分區,前面使用的是grep,現在完全可以都使用awk解決了
[root@centos7 data ]#df |awk '/^\/dev\/sd/'
/dev/sda2       52403200 4276856  48126344   9% /
/dev/sda3       31441920   33120  31408800   1% /data
/dev/sda1        1038336  157932    880404  16% /boot

> 統計/etc/fstab文件中文件系統的類型並統計次數
[root@centos7 data ]#awk '/^UUID/{print $3}' /etc/fstab|sort|uniq -c
      1 swap
      3 xfs

> 統計netstat -nt中外部ip地址連接的次數,並按照連接次數進行排序
[root@centos7 data ]#netstat -nt|awk -F'[ :]+' '/^tcp/{print $6}'|sort|uniq -c|sort -nr
      1 192.168.137.8
      1 192.168.137.6
      1 192.168.137.1

面試題:統計netstat -nt中併發連接數排在前10名的ip和連接數

  • relational expression: 關係表達式,結果爲“真”纔會被處理
    真:結果爲非0值,非空字符串
    假:結果爲空字符串或0值
> 由於""爲空,則爲假,不打印
[root@centos7 data ]#awk -F: '""{print $1}' /etc/passwd
> 由於空格爲真,則打印
[root@centos7 data ]#awk -F: '" "{print $1}' /etc/passwd
root
bin
daemon
> 爲0則爲假不打印;爲1則爲真打印
[root@centos7 data ]#awk -F: '0{print $1}' /etc/passwd
[root@centos7 data ]#awk -F: '1{print $1}' /etc/passwd
root
bin
daemon
adm

> true打印,false不打印
[root@centos7 data ]#seq 10|awk "i=9"
1
2
3
4
5
6
7
8
9
10
[root@centos7 data ]#seq 10|awk "i=0"
[root@centos7 data ]#

> 打印奇數:
[root@centos7 data ]#seq 10|awk 'i=!i'
1
3
5
7
9
說明:由於i最開始賦值爲空,則第一次!i=1,打印1;第二次!i=0,不打印2;第三次!i=1.打印i=3;第四次不打印,第五次打印5;所以打印的是奇數:即 1 3 5 7 9,可以通過seq 10|awk '{i=!i;print i}'查看執行過程

> 打印偶數
方法1:取反
[root@centos7 data ]#seq 10|awk '!(i=!i)'
2
4
6
8
10
方法2:直接對i賦值,任意非空值即可
[root@centos7 data ]#seq 10|awk -v i=1 'i=!i'
2
4
6
8
10

類比:sed打印奇數和偶數
[root@centos7 data ]#seq 10|sed -n '1~2p'
1
3
5
7
9
[root@centos7 data ]#seq 10|sed -n '2~2p'
2
4
6
8
10
  • 行範圍

    類比sed取行的方式:
    [root@centos7 data ]#sed -n '1,3p' /etc/passwd
    root:x:0:0:root:/root:/bin/bash
    bin:x:1:1:bin:/bin:/sbin/nologin
    daemon:x:2:2:daemon:/sbin:/sbin/nologin
    
    > 模式匹配
    [root@centos7 data ]#sed -n '/^b/,/^f/p' /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
    lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
    sync:x:5:0:sync:/sbin:/bin/sync
    shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
    halt:x:7:0:halt:/sbin:/sbin/halt
    mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
    operator:x:11:0:operator:/root:/sbin/nologin
    games:x:12:100:games:/usr/games:/sbin/nologin
    ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
    
    awk數字匹配行
    [root@centos7 data ]#awk -F:  '(NR>=1&&NR<=3){print NR,$0}' /etc/passwd
    1 root:x:0:0:root:/root:/bin/bash
    2 bin:x:1:1:bin:/bin:/sbin/nologin
    3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
    
    awk模式匹配行
    [root@centos7 data ]#awk -F: '/^root\>/,/^nobody\>/{print $1}' /etc/passwd
    root
    bin
    daemon
    adm
    lp
    sync
    shutdown
    halt
    mail
    operator
    games
    ftp
    nobody
    
    • BEGIN/END模式
BEGIN{} :處理文件之前執行
END{} : 處理文件之後執行

示例:
[root@centos7 data ]#awk -F: 'BEGIN {print "USER:XIN"}{print $0}END{print "end file"}' /etc/issue
USER:XIN
\S
Kernel \r on an \m

end file
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章