Linux中國

千面 awk

如果你僅使用 awk 選取一行中的特定文本,那麼你可能錯過了它的很多功能。在這篇文章中,我們會來看看使用 awk 可以幫你做一些其他的什麼事情,並提供一些例子。

提取數據列

awk 所提供的最簡單與最常用的功能便是從文件或管道傳輸的數據中選取特定的內容。默認使用空格當做分隔符,這非常簡單。

$ echo one two three four five | awk 『{print $4}』
four
$ who | awk 『{print $1}』
jdoe
fhenry

空格指的是一系列的 spacetab 字元。在下面所展示的命令里,awk 從提供的數據中篩選第一和第四項。

awk 命令也可以通過在其後增加文件名參數的方式從文本文件中獲取數據。

$ 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.」 ——海倫凱勒)

在這個例子中,awk 挑選了一行中的第一個、第五個和最後一個欄位。

命令中的 $NF 指定選取每行的最後一個欄位。這是因為 NF 代表一行中的 欄位數量 Number of Field ,也就是 23,而 $NF 就代表著那個欄位的值,也就是heart。最後的句號也包含進去了,因為它是最後一個字元串的一部分。

欄位能以任何有用的形式列印。在這個例子中,我們將欄位以日期的格式進行列印輸出。

$ date | awk '{print $4,$3,$2}'
2019 Nov 22

如果你省略了 awk 命令中欄位指示符之間的逗號,輸出將會擠成一個字元串。

$ date | awk '{print $4 $3 $2}'
2019Nov21

如果你將通常使用的逗號替換為連字元,awk 就會嘗試將兩個欄位的值相減——或許這並不是你想要的。它不會將連字元插入到輸出結果中。相反地,它對輸出做了一些數學計算。

$ date | awk '{print $4-$3-$2}'
1997

在這個例子中,它將年 「2019」 和日期 「22」 相減,並忽略了中間的 「Nov」。

如果你想要空格之外的字元作為輸出分隔符,你可以通過 OFS 輸出分隔符 output field separator )指定分隔符,就像這樣:

$ date | awk '{OFS="-"; print $4,$3,$2}'
2019-Nov-22

列印簡單文本

你也可以使用 awk 簡單地顯示一些文本。當然了,比起 awk 你可能更想使用 echo 命令。但換句話說,作為 awk 腳本的一部分,列印某些相關性文本將會非常實用。這裡有一個沒什麼用的例子:

$ awk 'BEGIN {print "Hello, World" }'
Hello, World

下面的例子更加合理,添加一行文本標籤來更好的辨識數據。

$ who | awk 'BEGIN {print "Current logins:"} {print $1}'
Current logins:
shs
nemo

指定欄位分隔符

不是所有的輸入都以空格作為分隔符的。如果你的文本通過其它的字元作為分隔符(例如:逗號、冒號、分號),你可以通過 -F 選項(輸入分隔符)告訴 awk

$ cat testfile
a:b:c,d:e
$ awk -F : '{print $2,$3}' testfile
b c,d

下面是一個更加有用的例子——從冒號分隔的 /etc/passwd 文件中獲取數據:

$ awk -F: '{print $1}' /etc/passwd | head -11
root
daemon
bin
sys
sync
games
man
lp
mail
news
uucp

篩選內容

你也可以使用 awk 命令評估欄位。例如你僅僅想列出 /etc/passwd 中的用戶賬號,就可以對第三個欄位做一些篩選。下面的例子中我們只關注大於等於 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
...

如果你想為輸出增加標題,可以添加 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

如果你想要不止一行的標題,你可以通過 "n" 分隔輸出:

$ awk -F":" 'BEGIN {print "user accountsn============="} $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 中進行數學計算

awk 提供了驚人的數學計算能力,並且可以開平方,算 log,算 tan 等等。

這裡有一對例子:

$ awk 'BEGIN {print sqrt(2019)}'
44.9333
$ awk 'BEGIN {print log(2019)}'
7.61036

想要詳細了解 awk 的數學計算能力,可以看《使用 awk 進行數學計算》這篇文章。

awk 腳本

你也可以使用 awk 寫一套單獨的腳本。下面的例子模仿了之前寫過的一個,不過還計算了系統里賬戶的數量。

#!/usr/bin/awk -f

# 這一行是注釋

BEGIN {
    printf "%sn","User accounts:"
    print "=============="
    FS=":"
    n=0
}

# 現在開始遍曆數據
{
    if ($3 >= 1000) {
        print $1
        n ++
    }
}

END {
    print "=============="
    print n " accounts"
}

注意 BEGIN 那一節是如何提供標題、指定欄位分隔符和初始化計數器的,它僅在腳本初始化時期執行。這個腳本也包含 END 節,它僅在中間所有命令處理完成之後運行,顯示了所有中間小節所篩選數據的最終行數(第三個欄位大於等於 1000)。

作為一個長存於 Unix 之上的命令,awk 依舊提供著非常有用的服務,這也是我幾十年前愛上 Unix 的原因之一。

via: https://www.networkworld.com/article/3454979/the-many-faces-of-awk.html

作者:Sandra Henry-Stocker 選題:lujun9972 譯者:LuuMing 校對:wxy

本文由 LCTT 原創編譯,Linux中國 榮譽推出


本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive

對這篇文章感覺如何?

太棒了
0
不錯
0
愛死了
0
不太好
0
感覺很糟
0
雨落清風。心向陽

    You may also like

    Leave a reply

    您的郵箱地址不會被公開。 必填項已用 * 標註

    此站點使用Akismet來減少垃圾評論。了解我們如何處理您的評論數據

    More in:Linux中國