幫助你排序文字檔案的 Awk 命令列或指令碼
Awk 是一個強大的工具,可以執行某些可能由其它常見實用程式(包括
sort
)來完成的任務。
Awk 是個普遍存在的 Unix 命令,用於掃描和處理包含可預測模式的文字。但是,由於它具有函式功能,因此也可以合理地稱之為程式語言。
令人困惑的是,有不止一個 awk。(或者,如果你認為只有一個,那麼其它幾個就是克隆。)有 awk
(由Aho、Weinberger 和 Kernighan 編寫的原始程式),然後有 nawk
、mawk
和 GNU 版本的 gawk
。GNU 版本的 awk 是該實用程式的一個高度可移植的自由軟體版本,具有幾個獨特的功能,因此本文是關於 GNU awk 的。
雖然它的正式名稱是 gawk
,但在 GNU+Linux 系統上,它的別名是 awk
,並用作該命令的預設版本。 在其他沒有帶有 GNU awk 的系統上,你必須先安裝它並將其稱為 gawk
,而不是 awk
。本文互換使用術語 awk
和 gawk
。
awk
既是命令語言又是程式語言,這使其成為一個強大的工具,可以處理原本留給 sort
、cut
、uniq
和其他常見實用程式的任務。幸運的是,開源中有很多冗餘空間,因此,如果你面臨是否使用 awk
的問題,答案可能是肯定的“隨便”。
awk
的靈活之美在於,如果你已經確定使用 awk
來完成一項任務,那麼無論接下來發生什麼,你都可以繼續使用 awk
。這包括對資料排序而不是按交付給你的順序的永恆需求。
樣本資料集
在探索 awk
的排序方法之前,請生成要使用的樣本資料集。保持簡單,這樣你就不會為極端情況和意想不到的複雜性所困擾。這是本文使用的樣本集:
Aptenodytes;forsteri;Miller,JF;1778;Emperor
Pygoscelis;papua;Wagler;1832;Gentoo
Eudyptula;minor;Bonaparte;1867;Little Blue
Spheniscus;demersus;Brisson;1760;African
Megadyptes;antipodes;Milne-Edwards;1880;Yellow-eyed
Eudyptes;chrysocome;Viellot;1816;Sothern Rockhopper
Torvaldis;linux;Ewing,L;1996;Tux
這是一個很小的資料集,但它提供了多種資料型別:
- 屬名和種名,彼此相關但又是分開的
- 姓,有時是以逗號開頭的首字母縮寫
- 代表日期的整數
- 任意術語
- 所有欄位均以分號分隔
根據你的教育背景,你可能會認為這是二維陣列或表格,或者只是行分隔的資料集合。你如何看待它只是你的問題,而 awk
只認識文字。由你決定告訴 awk
你想如何解析它。
只想排序
如果你只想按特定的可定義欄位(例如電子表格中的“單元格”)對文字資料集進行排序,則可以使用 sort 命令。
欄位和記錄
無論輸入的格式如何,都必須在其中找到模式才可以專注於對你重要的資料部分。在此示例中,資料由兩個因素定界:行和欄位。每行都代表一個新的記錄,就如你在電子表格或資料庫轉儲中看到的一樣。在每一行中,都有用分號(;
)分隔的不同的欄位(將其視為電子表格中的單元格)。
awk
一次只處理一條記錄,因此,當你在構造發給 awk
的這指令時,你可以只關注一行記錄。寫下你想對一行資料執行的操作,然後在下一行進行測試(無論是心理上還是用 awk
進行測試),然後再進行其它的一些測試。最後,你要對你的 awk
指令碼要處理的資料做好假設,以便可以按你要的資料結構提供給你資料。
在這個例子中,很容易看到每個欄位都用分號隔開。為簡單起見,假設你要按每行的第一欄位對列表進行排序。
在進行排序之前,你必須能夠讓 awk
只關注在每行的第一個欄位上,因此這是第一步。終端中 awk 命令的語法為 awk
,後跟相關選項,最後是要處理的資料檔案。
$ awk --field-separator=";" '{print $1;}' penguins.list
Aptenodytes
Pygoscelis
Eudyptula
Spheniscus
Megadyptes
Eudyptes
Torvaldis
因為欄位分隔符是對 Bash shell 具有特殊含義的字元,所以必須將分號括在引號中或在其前面加上反斜槓。此命令僅用於證明你可以專注於特定欄位。你可以使用另一個欄位的編號嘗試相同的命令,以檢視資料的另一個“列”的內容:
$ awk --field-separator=";" '{print $3;}' penguins.list
Miller,JF
Wagler
Bonaparte
Brisson
Milne-Edwards
Viellot
Ewing,L
我們尚未進行任何排序,但這是良好的基礎。
指令碼程式設計
awk
不僅僅是命令,它是一種具有索引、陣列和函式的程式語言。這很重要,因為這意味著你可以獲取要排序的欄位列表,將列表儲存在記憶體中,進行處理,然後列印結果資料。對於諸如此類的一系列複雜操作,在文字檔案中進行操作會更容易,因此請建立一個名為 sort.awk
的新檔案並輸入以下文字:
#!/bin/gawk -f
BEGIN {
FS=";";
}
這會將該檔案建立為 awk
指令碼,該指令碼中包含執行的行。
BEGIN
語句是 awk
提供的特殊設定功能,用於只需要執行一次的任務。定義內建變數 FS
,它代表欄位分隔符,並且與你在 awk
命令中使用 --field-separator
設定的值相同,它只需執行一次,因此它包含在 BEGIN
語句中。
awk 中的陣列
你已經知道如何通過使用 $
符號和欄位編號來收集特定欄位的值,但是在這種情況下,你需要將其儲存在陣列中而不是將其列印到終端。這是通過 awk
陣列完成的。awk
陣列的重要之處在於它包含鍵和值。 想象一下有關本文的內容;它看起來像這樣:author:"seth",title:"How to sort with awk",length:1200
。諸如作者、標題和長度之類的元素是鍵,跟著的內容為值。
在排序的上下文中這樣做的好處是,你可以將任何欄位分配為鍵,將任何記錄分配為值,然後使用內建的 awk
函式 asorti()
(按索引排序)按鍵進行排序。現在,隨便假設你只想按第二個欄位排序。
沒有被特殊關鍵字 BEGIN
或 END
引起來的 awk
語句是在每個記錄都要執行的迴圈。這是指令碼的一部分,該指令碼掃描資料中的模式並進行相應的處理。每次 awk
將注意力轉移到一條記錄上時,都會執行 {}
中的語句(除非以 BEGIN
或 END
開頭)。
要將鍵和值新增到陣列,請建立一個包含陣列的變數(在本示例指令碼中,我將其稱為 ARRAY
,雖然不是很原汁原味,但很清楚),然後在方括號中分配給它鍵,用等號(=
)連線值。
{ # dump each field into an array
ARRAY[$2] = $R;
}
在此語句中,第二個欄位的內容($2
)用作關鍵字,而當前記錄($R
)用作值。
asorti() 函式
除了陣列之外,awk
還具有一些基本函式,你可以將它們用作常見任務的快速簡便的解決方案。GNU awk中引入的函式之一 asorti()
提供了按鍵(索引)或值對陣列進行排序的功能。
你只能在對陣列進行填充後對其進行排序,這意味著此操作不能對每個新記錄都觸發,而只能在指令碼的最後階段進行。為此,awk
提供了特殊的 END
關鍵字。與 BEGIN
相反,END
語句僅在掃描了所有記錄之後才觸發一次。
將這些新增到你的指令碼:
END {
asorti(ARRAY,SARRAY);
# get length
j = length(SARRAY);
for (i = 1; i <= j; i++) {
printf("%s %s\n", SARRAY[i],ARRAY[SARRAY[i]])
}
}
asorti()
函式獲取 ARRAY
的內容,按索引對其進行排序,然後將結果放入名為 SARRAY
的新陣列(我在本文中發明的任意名稱,表示“排序的 ARRAY”)。
接下來,將變數 j
(另一個任意名稱)分配給 length()
函式的結果,該函式計算 SARRAY
中的項數。
最後,使用 for
迴圈使用 printf()
函式遍歷 SARRAY
中的每一項,以列印每個鍵,然後在 ARRAY
中列印該鍵的相應值。
執行該指令碼
要執行你的 awk
指令碼,先使其可執行:
$ chmod +x sorter.awk
然後針對 penguin.list
示例資料執行它:
$ ./sorter.awk penguins.list
antipodes Megadyptes;antipodes;Milne-Edwards;1880;Yellow-eyed
chrysocome Eudyptes;chrysocome;Viellot;1816;Sothern Rockhopper
demersus Spheniscus;demersus;Brisson;1760;African
forsteri Aptenodytes;forsteri;Miller,JF;1778;Emperor
linux Torvaldis;linux;Ewing,L;1996;Tux
minor Eudyptula;minor;Bonaparte;1867;Little Blue
papua Pygoscelis;papua;Wagler;1832;Gentoo
如你所見,資料按第二個欄位排序。
這有點限制。最好可以在執行時靈活選擇要用作排序鍵的欄位,以便可以在任何資料集上使用此指令碼並獲得有意義的結果。
新增命令選項
你可以通過在指令碼中使用字面值 var
將命令變數新增到 awk
指令碼中。更改指令碼,以使迭代子句在建立陣列時使用 var
:
{ # dump each field into an array
ARRAY[$var] = $R;
}
嘗試執行該指令碼,以便在執行指令碼時使用 -v var
選項將其按第三欄位排序:
$ ./sorter.awk -v var=3 penguins.list
Bonaparte Eudyptula;minor;Bonaparte;1867;Little Blue
Brisson Spheniscus;demersus;Brisson;1760;African
Ewing,L Torvaldis;linux;Ewing,L;1996;Tux
Miller,JF Aptenodytes;forsteri;Miller,JF;1778;Emperor
Milne-Edwards Megadyptes;antipodes;Milne-Edwards;1880;Yellow-eyed
Viellot Eudyptes;chrysocome;Viellot;1816;Sothern Rockhopper
Wagler Pygoscelis;papua;Wagler;1832;Gentoo
修正
本文演示瞭如何在純 GNU awk 中對資料進行排序。你可以對指令碼進行改進,以便對你有用,花一些時間在gawk
的手冊頁上研究 awk 函式並自定義指令碼以獲得更好的輸出。
這是到目前為止的完整指令碼:
#!/usr/bin/awk -f
# GPLv3 appears here
# usage: ./sorter.awk -v var=NUM FILE
BEGIN { FS=";"; }
{ # dump each field into an array
ARRAY[$var] = $R;
}
END {
asorti(ARRAY,SARRAY);
# get length
j = length(SARRAY);
for (i = 1; i <= j; i++) {
printf("%s %s\n", SARRAY[i],ARRAY[SARRAY[i]])
}
}
via: https://opensource.com/article/19/11/how-sort-awk
作者:Seth Kenlon 選題:lujun9972 譯者:wxy 校對:wxy
訂閱“Linux 中國”官方小程式來檢視
相關文章
- awk命令和指令碼的編寫啟蒙指令碼
- shell指令碼命令 執行python檔案&python命令列執行python程式碼指令碼Python命令列
- hadoop_批量命令指令碼&同步檔案指令碼Hadoop指令碼
- linux 中awk命令實現按照 指定的字元對文字進行排序Linux字元排序
- Windows從命令列建立文字檔案的兩種方式Windows命令列
- 使用 awk 命令統計文字
- Shell指令碼逐行處理文字檔案技巧指令碼
- Linux常用的文字檔案操作命令Linux
- Bash 指令碼如何建立臨時檔案:mktemp 命令和 trap 命令教程指令碼
- 文字檔案的編碼格式
- 命令列生成jar檔案命令列JAR
- 命令列批量截圖Node指令碼命令列指令碼
- pwn題命令列解題指令碼命令列指令碼
- 用python或使用Linux終端中的awk命令,處理檔案並提取其中的IP地址(文末有程式碼,可直接使用)PythonLinux
- 指令碼三兄弟 grep、awk、sed指令碼
- mv 命令 – 移動或改名檔案
- Golang命令列拷貝檔案Golang命令列
- 用 symfony/console 元件寫命令列指令碼元件命令列指令碼
- Jenkins 指令碼命令列應用總結Jenkins指令碼命令列
- Linux awk命令中如何刪除陣列Linux陣列
- Linux中 awk命令根據列的索引批次提取列的資料Linux索引
- 如何把 awk 指令碼移植到 Python指令碼Python
- 還在為找開源專案發愁麼?或許這個專案能幫助你
- linux的awk命令Linux
- 6.PHP包含檔案、終止指令碼、陣列指標PHP指令碼陣列指標
- awk命令
- 命令列技巧:分割檔案內容命令列
- Linux命令之grep/sed/awk等行轉列Linux
- Shell指令碼 | 抓取log檔案指令碼
- Linux rm命令:刪除檔案或目錄Linux
- awk指令碼語言程式設計指南指令碼程式設計
- Python 處理指令碼的命令列引數(二):使用clickPython指令碼命令列
- Python 處理指令碼的命令列引數(三):使用argparsePython指令碼命令列
- Linux:“awk”命令的妙用Linux
- Linux 命令列刪除指定副檔名檔案Linux命令列
- 使用命令列指令碼安裝PrestaShop1.6命令列指令碼REST
- 伺服器命令列常用的指令伺服器命令列
- 共享一個iptables的shell指令碼檔案指令碼