?awk是一個強(qiáng)大的文本處理工具。
awk把文件逐行的讀入,一行叫一條記錄,以空格為分隔符將每行切片,切開的部分叫域或者列或者字段,然后處理各個字段。
awk有3個不同版本:awk、nawk、gawk。
未作特別說明,一般指gawk,gawk是AWK的GNU版本。
awk其名稱源自它的創(chuàng)始人Alfred Aho 、Peter Weinberger和Brian Kernighan姓氏的首個字母。
一、調(diào)用awk的方法
1.命令行方式
awk [options] 'commands' input-file(s)
2.腳本方式
將所有的awk命令寫入一個文件,并使其可執(zhí)行,然后將awk命令解釋器作為腳本的首行,通過鍵入腳本名稱來調(diào)用。
相當(dāng)于shell腳本首行的#!/bin/sh換成#!/bin/awk
二、命令行方式用法
(一)語法格式
用法:awk [選項] -f 腳本文件 [--] 文件...
用法:awk [選項] [--] '程序' 文件...
(二)選項
-f 腳本文件, --file=腳本文件
-F fs, --field-separator=fs
-v var=val, --assign=var=val
-b, --characters-as-bytes
-c, --traditional
-C, --copyright
-d[文件], --dump-variables[=文件]
-D[文件], --debug[=文件]
-e '程序文本', --source='程序文本'
-E 文件, --exec=文件
-g, --gen-pot
-h, --help
-i 包含文件, --include=包含文件
-I, --trace
-l 庫, --load=庫
-L[fatal|invalid|no-ext], --lint[=fatal|invalid|no-ext]
-M, --bignum
-N, --use-lc-numeric
-n, --non-decimal-data
-o[文件], --pretty-print[=文件]
-O, --optimize
-p[文件], --profile[=文件]
-P, --posix
-r, --re-interval
-s, --no-optimize
-S, --sandbox
-t, --lint-old
-V, --version
(三)參數(shù)
1.程序
也叫腳本命令
格式為:
'模式{操作}'
它由兩部分組成,分別為模式和操作。模式也可以叫做條件或者地址。
整個腳本命令是用單引號’'括起。為了防止shell解析特殊字符。
如果是執(zhí)行多條腳本命令,格式為:
'模式1{命令1};模式2{命令2}...'
(1)模式
用來指定要處理的行。
模式可以是以下任意一個:
/正則表達(dá)式/:使用ERE。
關(guān)系表達(dá)式:使用運(yùn)算符操作,可以是字符串或數(shù)字的比較測試。
包含表達(dá)式:使用運(yùn)算符~(包含)和!~(不包含)。
BEGIN:如果模式是BEGIN,說明后面的操作只在程序開始時執(zhí)行一次。
END:如果模式是END,說明后面的操作只在程序結(jié)束時執(zhí)行一次。
模式1, 模式2:從匹配模式1的行到匹配模式2的行(包含該行)。
省略:表示處理所有行。
條件類型 | 條 件 | 說 明 |
---|---|---|
awk保留字 | BEGIN | 在 awk 程序一開始,尚未讀取任何數(shù)據(jù)之前執(zhí)行。BEGIN 后的動作只在程序開始時執(zhí)行一次 |
awk保留字 | END | 在 awk 程序處理完所有數(shù)據(jù),即將結(jié)束時執(zhí)行。END 后的動作只在程序結(jié)束時執(zhí)行一次 |
關(guān)系運(yùn)算符 | > | 大于 |
< | 小于 | |
>= | 大于等于 | |
<= | 小于等于 | |
== | 等于。用于判斷兩個值是否相等 | |
!= | 不等于 | |
A~B | 判斷字符串 A 中是否包含能匹配 B 表達(dá)式的子字符串 | |
A!~B | 判斷字符串 A 中是否不包含能匹配 B 表達(dá)式的子字符串 | |
正則表達(dá)式 | /正則/ | 匹配正則表達(dá)式的行 |
例如:
x>10:判斷變量 x 是否大于10;
x == y:判斷變量 x 是否等于變量 y;
A~B:判斷字符串 A 中是否包含能匹配 B 表達(dá)式的子字符串;
A!~B:判斷字符串 A 中是否不包含能匹配 B 表達(dá)式的子字符串;
(2)操作
操作由一個或多個命令、函數(shù)、表達(dá)式組成,之間由換行符或分號隔開,并位于大括號內(nèi),大括號不是必須的,但它們用于根據(jù)特定的模式對一系列指令分組,主要部分是:
變量或數(shù)組賦值
輸入輸出
內(nèi)置函數(shù)
控制流語句
2.一個或多個文件
(四)內(nèi)置變量
變量 | 描述 |
---|---|
$n | 當(dāng)前記錄的第n個字段,字段間由FS分隔,n從1開始 |
$0 | 完整的輸入記錄 |
ARGC | 命令行參數(shù)的數(shù)目 |
ARGIND | 命令行中當(dāng)前文件的位置(從0開始算) |
ARGV | 包含命令行參數(shù)的數(shù)組 |
CONVFMT | 數(shù)字轉(zhuǎn)換格式(默認(rèn)值為%.6g)ENVIRON環(huán)境變量關(guān)聯(lián)數(shù)組 |
ERRNO | 最后一個系統(tǒng)錯誤的描述 |
FIELDWIDTHS | 字段寬度列表(用空格鍵分隔) |
FILENAME | 當(dāng)前文件名 |
FNR | 各文件分別計數(shù)的行號 |
FS | 字段分隔符(默認(rèn)是任何空格) |
IGNORECASE | 如果為真,則進(jìn)行忽略大小寫的匹配 |
NF | 一條記錄的字段的數(shù)目 |
NR | 已經(jīng)讀出的記錄數(shù),就是行號,從1開始 |
OFMT | 數(shù)字的輸出格式(默認(rèn)值是%.6g) |
OFS | 輸出字段分隔符,默認(rèn)值與輸入字段分隔符一致。 |
ORS | 輸出記錄分隔符(默認(rèn)值是一個換行符) |
RLENGTH | 由match函數(shù)所匹配的字符串的長度 |
RS | 記錄分隔符(默認(rèn)是一個換行符) |
RSTART | 由match函數(shù)所匹配的字符串的第一個位置 |
SUBSEP | 數(shù)組下標(biāo)分隔符(默認(rèn)值是/034) |
(五)示例用法
1.使用內(nèi)置函數(shù)
最常用的內(nèi)置函數(shù)就是輸出函數(shù)。awk中同時提供了print和printf兩種打印輸出的函數(shù)。
(1)print
是默認(rèn)命令。
print函數(shù)的參數(shù)可以是變量、數(shù)值、字符串。字符串必須用雙引號引用,參數(shù)用逗號分隔。如果沒有逗號,參數(shù)就串聯(lián)在一起而無法區(qū)分。
print函數(shù)的輸出會把各參數(shù)用空格分開。print函數(shù)默認(rèn)會在每行后面加上ORS。
如,
'{print key, "=" value}'
(2)printf
printf函數(shù),其用法和c語言中printf基本相似,可以格式化字符串,輸出復(fù)雜時,printf更加好用,代碼更易懂。需要特別注意的是使用printf時默認(rèn)是不會換行的,需要手動加\n。
printf 語句的格式如下:
printf(format, value1, value2, ..., valuen)
其中format是格式字符串,包含要原樣打印的文本和規(guī)格(specification)。
一個規(guī)格是一個%符后面跟著一些字符,用來控制一個 value的格式。
第一個規(guī)格說明如何打印value1,第二個說明如何打印value2,依次類推。因此,有多少value要打印,在format中就要有多少個規(guī)格。
規(guī)格 | 說明 |
---|---|
%d | 十進(jìn)制有符號整數(shù) |
%u | 十進(jìn)制無符號整數(shù) |
%f | 浮點數(shù) |
%s | 字符串 |
%c | 單個字符 |
%p | 指針的值 |
%e | 指數(shù)形式的浮點數(shù) |
%x | 無符號以十六進(jìn)制表示的整數(shù) |
%o | 無符號以八進(jìn)制表示的整數(shù) |
%g | 自動選擇合適的表示法 |
如,
'{ printf("total pay for %s is $%.2f\n", $1, $2 * $3) }'
輸出樣例:
total pay for Beth is $0.00
total pay for Dan is $0.00
total pay for Kathy is $40.00
total pay for Mark is $100.00
total pay for Mary is $121.00
total pay for Susie is $76.50
第一個規(guī)格是%s,說明以字符串的方式打印第一個值 $1。
第二個是%.2f,說明以數(shù)字的方式打印第二個值$2*$3,并保留小數(shù)點后面兩位。
規(guī)格字符串中其他東西,包括美元符號,原樣打印。
字符串尾部的\n代表開始新的一行,使得后續(xù)輸出將從下一行開始。
'{ printf("%-8s $%6.2f\n", $1, $2 * $3) }'
Beth $ 0.00
Dan $ 0.00
Kathy $ 40.00
Mark $100.00
Mary $121.00
Susie $ 76.50
第一個規(guī)格%-8s將一個姓名以字符串形式在8個字符寬度的字段中左對齊輸出。
第二個規(guī)格%6.2f將薪酬以數(shù)字的形式,保留小數(shù)點后兩位,在6個字符寬度的字段中輸出。
(3)length函數(shù)
length([string])返回字符串的長度。比如:length("abc")返回3
length()返回
$0的長度。
?從文件中找出長度大于 80 的行:
awk 'length()>80' log.txt
2.使用外部命令
(1)使用system函數(shù)執(zhí)行外部命令
①語法格式
awk '{system("command")}' file
system的返回值是command執(zhí)行的返回值
command必須使用雙引號引起來。
②示例
awk 'BEGIN{system("ls")}' file.txt
(2)使用管道
awk中的管道概念和shell的管道類似,都是使用"|"符號。如果在awk程序中打開了管道,必須先關(guān)閉該管道才能打開另一個管道。也就是說一次只能打開一個管道。管道一旦打開,就會保持打開狀態(tài)直至awk退出。
又分為兩種:
一種是配合getline
一種是配合print
①配合getline
1)格式
awk '{"command" | getline [var]}' file
var是可選參數(shù),用于存儲命令執(zhí)行后的標(biāo)準(zhǔn)輸出,默認(rèn)情況下結(jié)果輸出到$0
command必須用雙引號引起來。
執(zhí)行的結(jié)果緩存于pipe中,再傳送給awk處理,如果有多行數(shù)據(jù),awk的getline命令可能調(diào)用多次。
2)示例
awk '{"curl www.baidu.com" | getline result; print(result);}' file.txt
$awk 'BEGIN{ while(("ls" | getline d) > 0) print d}' file.txt
②配合print或printf
1)格式
awk '{print ... | "command"}' file
command必須用雙引號引用起來。
output是先緩存在pipe中,等輸出完畢后再調(diào)用shell命令處理,shell命令只處理一次,而且處理的時機(jī)是“awk程序結(jié)束時,或者管道關(guān)閉時(需要顯式的關(guān)閉管道)”
2)示例
$ awk 'BEGIN{print "foobar" | "echo eew"}' file.txt
eew
$ awk 'BEGIN{count=0} /west/{count++} {printf("%s %stt%-15sn", $3,$4,$1) | "sort +1"} END{close("sort +1"); printf("The number of sales pers in the western"); print "region is " count "."}' file.txt
printf函數(shù)用于將輸出格式化并發(fā)送給管道。所有輸出集齊后一同發(fā)送給sort命令。
必須用與打開時完全相同的命令來關(guān)閉管道(sort +1),否則END塊中的語句將與前面的輸出一起被排序。
此處的sort命令只執(zhí)行一次。
awk調(diào)用外部命令都是新開一個shell,所以要注意當(dāng)前shell變量與新開shell變量問題
root@ubuntu:~# abc=12345567890
root@ubuntu:~# awk 'BEGIN{system("echo $abc")}'
root@ubuntu:~#
root@ubuntu:~# export abc=12345567890
root@ubuntu:~# awk 'BEGIN{system("echo $abc")}'
12345567890
root@ubuntu:~#
root@ubuntu:~# abc=1234567890
root@ubuntu:~# awk 'BEGIN{print "echo","$abc"| "/bin/bash"}'
root@ubuntu:~#
root@ubuntu:~# export abc=1234567890
root@ubuntu:~# awk 'BEGIN{print "echo","$abc"| "/bin/bash"}'
1234567890
root@ubuntu:~#
3.使用內(nèi)置變量
(1)變量NF
表示當(dāng)前行有多少個字段,字段從1開始編號。
$NF就代表最后一個字段。
$ echo 'this is a test' | awk '{print $NF}'
test
$(NF-1)代表倒數(shù)第二個字段。
$ awk -F ':' '{print $1, $(NF-1)}' demo.txt
root /root
daemon /usr/sbin
bin /bin
sys /dev
sync /bin
(2)刪除列
比如,刪除第2列,讓它等于空
awk '{$2 = ""; print $0}' file
awk '{$2 = null; print $0}' file
但是這種寫法會多出一個空格,如下例:
[root@centos79 test3]# cat a.txt
3 5 6 2
s g 3 5
c f h e
[root@centos79 test3]# awk '{$2 = ""; print $0}' a.txt
3 6 2
s 3 5
c h e
刪除第二列,不留空格的寫法如下
awk '{$2 = "\b"; print $0}' file
如下例:
[root@centos79 test3]# cat a.txt
3 5 6 2
s g 3 5
c f h e
[root@centos79 test3]# awk '{$2 = "\b"; print $0}' a.txt
3 6 2
s 3 5
c h e
(3)統(tǒng)計/etc/passwd文件名,每行的行號,每行的列數(shù)
#awk -F':' '{print "filename:" FILENAME ",linenumber:" NR ",columns:" NF}' /etc/passwd
filename:/etc/passwd,linenumber:1,columns:7
filename:/etc/passwd,linenumber:2,columns:7
filename:/etc/passwd,linenumber:3,columns:7
filename:/etc/passwd,linenumber:4,columns:7
(4)使用自定義變量
awk中自定義變量不需要聲明,默認(rèn)初始值是0,所以不用初始化,可以直接使用。
例子:計算文件大小
$ ls -l *.txt | awk '{sum+=$5} END {print sum}'
666581
4.直接使用shell變量。
(1)是“雙引號+單引號+shell變量+單引號+雙引號”的格式
awk '{print "'$shellvar'"}' filename
$ foo=bar
$ awk 'BEGIN{print "'$foo'"}' file.txt
bar
(2)是“雙引號+單引號+雙引號+shell變量+雙引號+單引號+雙引號”的格式
awk '{print "'"$shellvar"'"}' filename
如果變量的值中包含空格,為了shell不把空格作為分隔符,則應(yīng)使用這種方法
(3)export變量,然后在awk中使用ENVIRON[“var”]形式獲取環(huán)境變量的值
awk '{print ENVIRON["var"]}' filename
$ export foo=bar
$ awk 'BEGIN{print ENVIRON["foo"]}' file.txt
bar
(4)使用-v選項
定義變量時,讓其值等于shell變量的值
示例:
foo=bar
awk -v awkfoo=$foo '{print awkfoo}' file.txt
實例:
$ awk -va=1 '{print $1,$1+a}' log.txt
---------------------------------------------
2 3
3 4
This's 1
10 11
$ awk -va=1 -vb=s '{print $1,$1+a,$1b}' log.txt
---------------------------------------------
2 3 2s
3 4 3s
This's 1 This'ss
10 11 10s
5.-F選項
默認(rèn)情況下,awk會使用空格分割一行數(shù)據(jù),但是可以使用-F選項指定分隔符。-F后面的分隔符可以用雙引號,也可以用單引號,也可以不用引號。
Num,Name,Company,Product
1,Jobs,Apple,iPhone
2,Jack,Alibaba,taobao
3,Pony,Tencent,wechat
awk -F"," '{print $2"\t"$3}' form.txt
Name Company
Jobs Apple
Jack Alibaba
Pony Tencent
這里的選項 -F “,” 就表示以每行數(shù)據(jù)中的逗號為分隔符,來切分?jǐn)?shù)據(jù)。
實例:
#使用","分割
$ awk -F, '{print $1,$2}' log.txt
2 this is a test
3 Are you like awk
This's a test
10 There are orange apple
# 或者使用內(nèi)建變量
$ awk 'BEGIN{FS=","} {print $1,$2}' log.txt
2 this is a test
3 Are you like awk
This's a test
10 There are orange apple
# 使用多個分隔符
$ awk -F '[ ,]' '{print $1,$2,$5}' log.txt
2 this test
3 Are awk
This's a
10 There apple
6.-f選項從文件中讀取程序
awk 允許將腳本命令存儲到文件中,然后再在命令行中引用,比如:
假設(shè)有這么一個文件(學(xué)生成績表):
$ cat score.txt
Marry 2143 78 84 77
Jack 2321 66 78 45
Tom 2122 48 77 71
Mike 2537 87 97 95
Bob 2415 40 57 62
我們的 awk 腳本如下:
$ cat cal.awk
#!/bin/awk
#運(yùn)行前
BEGIN {
math = 0
english = 0
computer = 0
printf "NAME NO. MATH ENGLISH COMPUTER TOTAL\n"
printf "---------------------------------------------\n"
}
#運(yùn)行中
{
math+=$3
english+=$4
computer+=$5
printf "%-6s %-6s %4d %8d %8d %8d\n", $1, $2, $3,$4,$5, $3+$4+$5
}
#運(yùn)行后
END {
printf "---------------------------------------------\n"
printf " TOTAL:%10d %8d %8d \n", math, english, computer
printf "AVERAGE:%10.2f %8.2f %8.2f\n", math/NR, english/NR, computer/NR?
}
我們來看一下執(zhí)行結(jié)果:
$ awk -f cal.awk score.txt
NAME NO. MATH ENGLISH COMPUTER TOTAL
---------------------------------------------
Marry 2143 78 84 77 239
Jack 2321 66 78 45 189
Tom 2122 48 77 71 196
Mike 2537 87 97 95 279
Bob 2415 40 57 62 159
---------------------------------------------
TOTAL: 319 393 350
AVERAGE: 63.80 78.60 70.00
7.BEGIN END模式
awk 'BEGIN{ commands } pattern{ commands } END{ commands }'
第一步:執(zhí)行BEGIN{ commands }語句塊中的語句;
第二步:從文件或標(biāo)準(zhǔn)輸入(stdin)讀取一行,然后執(zhí)行pattern{ commands }語句塊,它逐行掃描文件,從第一行到最后一行重復(fù)這個過程,直到文件全部被讀取完畢。
第三步:當(dāng)讀至輸入流末尾時,執(zhí)行END{ commands }語句塊。
BEGIN語句塊在awk開始從輸入流中讀取行之前執(zhí)行,這是一個可選的語句塊,比如變量初始化、打印輸出表格的表頭等語句通??梢詫懺贐EGIN語句塊中。
END語句塊在awk從輸入流中讀取完所有的行之后即被執(zhí)行,比如打印所有行的分析結(jié)果這類信息匯總都是在END語句塊中完成,它也是一個可選語句塊。
pattern語句塊中的通用命令是最重要的部分,它也是可選的。如果沒有提供pattern語句塊,則默認(rèn)執(zhí)行{ print },即打印每一個讀取到的行,awk讀取的每一行都會執(zhí)行該語句塊。
示例
echo -e "A line 1\nA line 2" | awk 'BEGIN{ print "Start" } { print } END{ print "End" }'
Start
A line 1
A line 2
End
8.條件表達(dá)式模式
(1)下面用一個綜合的例子來說明awk的條件判斷和數(shù)值計算,有這樣一組數(shù)據(jù)保存為pay.txt:
Name 1st 2nd 3rd
VBird 23000 24000 25000
DMTsai 21000 20000 23000
Bird2 43000 42000 41000
現(xiàn)在想加一列"Total",計算每一行的數(shù)值總和。
用awk可以完成這個需求:
awk 'NR==1 {printf "%10s %10s %10s %10s %10s \n",$1,$2,$3,$4,"Total"};NR>1 {printf "%10s %10s %10s %10s %10s \n",$1,$2,$3,$4,$2+$3+$4}' pay.txt
(2)過濾第一列大于2的行
$ awk '$1>2' log.txt
#輸出
3 Are you like awk
This's a test
10 There are orange,apple,mongo
(3)過濾第一列等于2的行
$ awk '$1==2 {print $1,$3}' log.txt
#輸出
2 is
(4)過濾第一列大于2并且第二列等于’Are’的行
$ awk '$1>2 && $2=="Are" {print $1,$2,$3}' log.txt
#輸出
3 Are you
9.使用循環(huán)語句
(1)輸出每行的前5列,并按行輸出
awk '{for(i=1;i<6;i++)printf("%s ",$i);printf("\n")}' input.file
(2)輸出多列,并更改分隔符為TAB
awk '{for(i=2;i<=NF;i++)printf("%s\t",$i);printf("\n")}' input.file
(3)每三行作為一列輸出文章來源:http://www.zghlxwxcb.cn/news/detail-493560.html
awk '{if(NR%3 != 0){ORS="\t"}else{ORS="\n"}print}' input.file
(4)打印九九乘法表文章來源地址http://www.zghlxwxcb.cn/news/detail-493560.html
seq 9 | sed 'H;g' | awk -v RS='' '{for(i=1;i<=NF;i++)printf("%dx%d=%d%s", i, NR, i*NR, i==NR?"\n":"\t")}'
到了這里,關(guān)于awk命令的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!