帶你了解千面得awk命令
awk
命令不僅提供了簡單的輸入字符串篩選功能,還包含提取數(shù)據(jù)列、打印簡單文本、篩選內(nèi)容——甚至做一些數(shù)學(xué)計(jì)算。
如果你僅使用 awk
選取一行中的特定文本,那么你可能錯(cuò)過了它的很多功能。在這篇文章中,我們會(huì)來看看使用 awk
可以幫你做一些其他的什么事情,并提供一些例子。
提取數(shù)據(jù)列
awk
所提供的最簡單與最常用的功能便是從文件或管道傳輸?shù)臄?shù)據(jù)中選取特定的內(nèi)容。默認(rèn)使用空格當(dāng)做分隔符,這非常簡單。
$ echo one two three four five | awk ‘{print $4}’
four
$ who | awk ‘{print $1}’
jdoe
fhenry
空格指的是一系列的 space
或 tab
字符。在下面所展示的命令里,awk
從提供的數(shù)據(jù)中篩選第一和第四項(xiàng)。
awk
命令也可以通過在其后增加文件名參數(shù)的方式從文本文件中獲取數(shù)據(jù)。
$ awk '{print $1,$5,$NF}' HelenKellerQuote
The beautiful heart.
(LCTT 譯注:“The best and most beautiful things in the world can not be seen or even touched , they must be felt with heart.” ——海倫凱勒)
在這個(gè)例子中,awk
挑選了一行中的第一個(gè)、第五個(gè)和最后一個(gè)字段。
命令中的 $NF
指定選取每行的最后一個(gè)字段。這是因?yàn)?NF
代表一行中的字段數(shù)量,也就是 23,而 $NF
就代表著那個(gè)字段的值,也就是heart
。最后的句號也包含進(jìn)去了,因?yàn)樗亲詈笠粋€(gè)字符串的一部分。
字段能以任何有用的形式打印。在這個(gè)例子中,我們將字段以日期的格式進(jìn)行打印輸出。
$ date | awk '{print $4,$3,$2}'
2019 Nov 22
如果你省略了 awk
命令中字段指示符之間的逗號,輸出將會(huì)擠成一個(gè)字符串。
$ date | awk '{print $4 $3 $2}'
2019Nov21
如果你將通常使用的逗號替換為連字符,awk
就會(huì)嘗試將兩個(gè)字段的值相減——或許這并不是你想要的。它不會(huì)將連字符插入到輸出結(jié)果中。相反地,它對輸出做了一些數(shù)學(xué)計(jì)算。
$ date | awk '{print $4-$3-$2}'
1997
在這個(gè)例子中,它將年 “2019” 和日期 “22” 相減,并忽略了中間的 “Nov”。
如果你想要空格之外的字符作為輸出分隔符,你可以通過 OFS
(輸出分隔符)指定分隔符,就像這樣:
$ date | awk '{OFS="-"; print $4,$3,$2}'
2019-Nov-22
打印簡單文本
你也可以使用 awk
簡單地顯示一些文本。當(dāng)然了,比起 awk
你可能更想使用 echo
命令。但換句話說,作為 awk
腳本的一部分,打印某些相關(guān)性文本將會(huì)非常實(shí)用。這里有一個(gè)沒什么用的例子:
$ awk 'BEGIN {print "Hello, World" }'
Hello, World
下面的例子更加合理,添加一行文本標(biāo)簽來更好的辨識(shí)數(shù)據(jù)。
$ who | awk 'BEGIN {print "Current logins:"} {print $1}'
Current logins:
shs
nemo
指定字段分隔符
不是所有的輸入都以空格作為分隔符的。如果你的文本通過其它的字符作為分隔符(例如:逗號、冒號、分號),你可以通過 -F
選項(xiàng)(輸入分隔符)告訴 awk
:
$ cat testfile
a:b:c,d:e
$ awk -F : '{print $2,$3}' testfile
b c,d
下面是一個(gè)更加有用的例子——從冒號分隔的 /etc/passwd
文件中獲取數(shù)據(jù):
$ awk -F: '{print $1}' /etc/passwd | head -11
root
daemon
bin
sys
sync
games
man
lp
news
uucp
篩選內(nèi)容
你也可以使用 awk
命令評估字段。例如你僅僅想列出 /etc/passwd
中的用戶賬號,就可以對第三個(gè)字段做一些篩選。下面的例子中我們只關(guān)注大于等于 1000 的 UID:
$ awk -F":" ' $3 >= 1000 ' /etc/passwd
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
shs:x:1000:1000:Sandra Henry-Stocker,,,:/home/shs:/bin/bash
nemo:x:1001:1001:Nemo,,,:/home/nemo:/usr/bin/zsh
dory:x:1002:1002:Dory,,,:/home/dory:/bin/bash
...
如果你想為輸出增加標(biāo)題,可以添加 BEGIN
從句:
$ awk -F":" 'BEGIN {print "user accounts:"} $3 >= 1000 ' /etc/passwd
user accounts:
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
shs:x:1000:1000:Sandra Henry-Stocker,,,:/home/shs:/bin/bash
nemo:x:1001:1001:Nemo,,,:/home/nemo:/usr/bin/zsh
dory:x:1002:1002:Dory,,,:/home/dory:/bin/bash
如果你想要不止一行的標(biāo)題,你可以通過 "\n"
分隔輸出:
$ awk -F":" 'BEGIN {print "user accounts\n============="} $3 >= 1000 ' /etc/passwd
user accounts
=============
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
shs:x:1000:1000:Sandra Henry-Stocker,,,:/home/shs:/bin/bash
nemo:x:1001:1001:Nemo,,,:/home/nemo:/usr/bin/zsh
dory:x:1002:1002:Dory,,,:/home/dory:/bin/bash
在 awk 中進(jìn)行數(shù)學(xué)計(jì)算
awk
提供了驚人的數(shù)學(xué)計(jì)算能力,并且可以開平方,算 log
,算 tan
等等。
這里有一對例子:
$ awk 'BEGIN {print sqrt(2019)}'
44.9333
$ awk 'BEGIN {print log(2019)}'
7.61036
想要詳細(xì)了解 awk
的數(shù)學(xué)計(jì)算能力,可以看《使用 awk 進(jìn)行數(shù)學(xué)計(jì)算》這篇文章。
awk 腳本
你也可以使用 awk
寫一套單獨(dú)的腳本。下面的例子模仿了之前寫過的一個(gè),不過還計(jì)算了系統(tǒng)里賬戶的數(shù)量。
#!/usr/bin/awk -f
# 這一行是注釋
BEGIN {
printf "%s\n","User accounts:"
print "=============="
FS=":"
n=0
}
# 現(xiàn)在開始遍歷數(shù)據(jù)
{
if ($3 >= 1000) {
print $1
n ++
}
}
END {
print "=============="
print n " accounts"
}
注意 BEGIN
那一節(jié)是如何提供標(biāo)題、指定字段分隔符和初始化計(jì)數(shù)器的,它僅在腳本初始化時(shí)期執(zhí)行。這個(gè)腳本也包含 END
節(jié),它僅在中間所有命令處理完成之后運(yùn)行,顯示了所有中間小節(jié)所篩選數(shù)據(jù)的最終行數(shù)(第三個(gè)字段大于等于 1000)。
作為一個(gè)長存于 Unix 之上的命令,awk
依舊提供著非常有用的服務(wù),這也是我?guī)资昵皭凵?Unix 的原因之一。