目錄
基本介紹
命令格式
awk基本使用
命令行讀取程序腳本
數據字段變量
腳本中使用多個命令
文件中讀取程序
處理數據前運行腳本(BEGIN)
處理數據后運行腳本(END)
awk高級用法
變量
內建變量
自定義變量
數組
定義數組變量
遍歷數組變量
刪除數組變量
使用模式
正則表達式
匹配操作符
數學表達式
結構化命令
if語句
while語句
do-while語句
for語句
內建函數
數學函數
字符串函數
時間函數
自定義函數
基本介紹
AWK是一種強大的文本處理工具,常用于在 Linux/Unix 系統中對文本文件進行模式掃描和處理。它非常適合處理結構化文本數據(如日志文件、CSV 文件等),并支持按行處理、字段提取、條件過濾和計算等操作。在awk編程語言中,你可以做下面的事情:
定義變量來保存數據; |
使用算術和字符串操作符來處理數據; |
使用結構化編程概念(比如 if-then 語句和循環)來為數據處理增加處理邏輯; |
通過提取數據文件中的數據元素,將其重新排列或格式化,生成格式化報告。 |
命令格式
awk options program file
常用選項 | 描述 |
-F | 指定行中劃分數據字段的字段分隔符 |
-f | 從指定的文件中讀取程序 |
-v | 定義 awk 程序中的一個變量及其默認值 |
-mf | 指定要處理的數據文件中的最大字段數 |
-mr | 指定數據文件中的最大數據行數 |
awk基本使用
命令行讀取程序腳本
[root@localhost ~]# awk '{print "Hello World!"}'
1
Hello World!
1
Hello World!
print命令會將文本打印到標準輸出,若沒有指定文本文件會從標準輸入中接受數據。?
數據字段變量
$0 | 代表整個文本行; |
$1 | 代表文本行中的第 1 個數據字段; |
$2 | 代表文本行中的第 2 個數據字段; |
$n | 代表文本行中的第 n 個數據字段。 |
以下為從data2.txt文件中獲取每行的第一個字段和第二個字段。
[root@localhost ~]# cat data2.txt
One line of test text.
Two lines of test text.
Three lines of test text.[root@localhost ~]# awk '{print $1,$2}' data2.txt
One line
Two lines
Three lines
此外也可以用-F選項指定字段分割符
[root@localhost ~]# awk -F : '{print $1}' /etc/passwd | head -3
root
bin
daemon
腳本中使用多個命令
在腳本中運行多個命令,若在同一行中,只需在兩條命令中加 ; 即可。
[root@localhost ~]# awk '{print "hello";print "world"}'hello
world
?若在不同行中,則無需 ;。
[root@localhost ~]# awk '{
> print "hello"
> print "world"
> }'hello
world
文件中讀取程序
awk使用 -f 參數從指定文件中讀取程序
[root@localhost ~]# cat script2.awk
{print $1,"'s home is",$6
}[root@localhost ~]# awk -F : -f script2.awk /etc/passwd | head -3
root 's home is /root
bin 's home is /bin
daemon 's home is /sbin
處理數據前運行腳本(BEGIN)
[root@localhost ~]# cat data3.txt
Line 1
Line 2
Line 3
[root@localhost ~]# awk 'BEGIN {print "data3.txt:"}{print $0}' data3.txt
data3.txt:
Line 1
Line 2
Line 3
處理數據后運行腳本(END)
[root@localhost ~]# awk 'BEGIN {print "data3.txt:"}{print $0}END{print "end of file"}' data3.txt
data3.txt:
Line 1
Line 2
Line 3
end of file
awk高級用法
變量
- 內建變量
- 自定義變量
awk有一些自帶的內建變量,用于存放處理數據文件中的數據字段和記錄的信息等。
內建變量
- 字段和記錄分隔符變量
變量 | 描述 |
FIELDWIDTHS | 由空格分隔的一列數字,定義了每個數據字段確切寬度 |
FS | 輸入字段分隔符 |
RS | 輸入記錄分隔符 |
OFS | 輸出字段分隔符 |
ORS | 輸出記錄分隔符 |
?在BEGIN中用FS指定輸入字段分割符,OFS指定輸出字段分隔符,若不指定則都為空格。
[root@localhost ~]# cat data1.txt
data11,data12,data13,data14,data15
data21,data22,data23,data24,data25
data31,data32,data33,data34,data35[root@localhost ~]# awk 'BEGIN{FS=","}{print $1,$2,$3}' data1.txt
data11 data12 data13
data21 data22 data23
data31 data32 data33[root@localhost ~]# awk 'BEGIN{FS=",";OFS="-"}{print $1,$2,$3}' data1.txt
data11-data12-data13
data21-data22-data23
data31-data32-data33
?FIELDWIDTHS可以精確的指定每個字段的長度,這種方法不適用與變長的字段。
[root@localhost ~]# awk 'BEGIN{FIELDWIDTHS="3 5 2 5"}{print $1,$2,$3,$4}' data1.txt
dat a11,d at a12,d
dat a21,d at a22,d
dat a31,d at a32,d
?在awk中,可以根據情況指定RS輸入記錄分割符,以應對特殊情況。
[root@localhost ~]# cat data4.txt
Riley Mullen
123 Main Street
Chicago, IL 60601
(312)555-1234Frank Williams
456 Oak Street
Indianapolis, IN 46201
(317)555-9876Haley Snell
4231 Elm Street
Detroit, MI 48201
(313)555-4938[root@localhost ~]# awk 'BEGIN{FS="\n";RS=""}{print $1,$4}' data4.txt
Riley Mullen (312)555-1234
Frank Williams (317)555-9876
Haley Snell (313)555-4938
- 數據變量
變量 | 描述 |
ARGC | 當前命令行參數個數 |
ARGIND | 當前文件在 ARGV 中的位置 |
ARGV | 包含命令行參數的數組 |
CONVFMT | 數字的轉換格式(參見 printf 語句),默認值為 %.6 g |
ENVIRON | 當前 shell 環境變量及其值組成的關聯數組 |
ERRNO | 當讀取或關閉輸入文件發生錯誤時的系統錯誤號 |
FILENAME | 用作 awk 輸入數據的數據文件的文件名 |
FNR | 當前數據文件中的數據行數 |
IGNORECASE | 設成非零值時,忽略 awk 命令中出現的字符串的字符大小寫 |
NF | 數據文件中的字段總數 |
NR | 已處理的輸入記錄數 |
OFMT | 數字的輸出格式,默認值為 %.6 g |
RLENGTH | 由 match 函數所匹配的子字符串的長度 |
RSTART | 由 match 函數所匹配的子字符串的起始位置 |
自定義變量
[root@localhost ~]# awk 'BEGIN{testing="hello world"}{print testing}'hello world
自定義變量除了可以存字符串,也可以存數值,并進行數值運算
[root@localhost ~]# awk 'BEGIN{a=10
> a=a+15
> }
> {
> print a
> }'25
也可以在命令行上給變量賦值
[root@localhost ~]# cat data1.txt
data11,data12,data13,data14,data15
data21,data22,data23,data24,data25
data31,data32,data33,data34,data35[root@localhost ~]# awk -F , '{print $n}' n=3 data1.txt
data13
data23
data33
但這種方法賦值的變量在BEGIN中不生效
[root@localhost ~]# awk -F , 'BEGIN{print n}{print $n}' n=3 data1.txt data13
data23
data33
也可以使用 -v 參數賦值變量,這樣聲明的變量在BEGIN中也能使用
[root@localhost ~]# awk -F , -v n=3 'BEGIN{print n}{print $n}' data1.txt
3
data13
data23
data33
數組
定義數組變量
[root@localhost ~]# cat script3.awk
BEGIN{str["name"] = "xiaoming"str["age"] = 18str["sex"] = "man"
}
{print str["name"]
}
[root@localhost ~]# awk -f script3.awk xiaoming
遍歷數組變量
在awk中遍歷數組,可以使用for in語句
for (var in array)
{
statements
}
?這個for語句會在每次循環時將關聯數組array的下一個索引值賦給變量var,然后執行一遍 statements。
[root@localhost ~]# cat script3.awk
BEGIN{str["name"] = "xiaoming"str["age"] = 18str["sex"] = "man"
}
{for(s in str){print s,":",str[s]}
}
[root@localhost ~]# awk -f script3.awk age : 18
sex : man
name : xiaoming
刪除數組變量
delete array[index]
[root@localhost ~]# cat script3.awk
BEGIN{str["name"] = "xiaoming"str["age"] = 18str["sex"] = "man"
}
{delete str["age"]for(s in str){print s,":",str[s]}
}
[root@localhost ~]# awk -f script3.awk sex : man
name : xiaoming
使用模式
正則表達式
[root@localhost ~]# cat data5.txt
Alice 25 Engineer
Bob 30 Doctor
Charlie 22 Student
David 35 Lawyer
Eve 28 Artist[root@localhost ~]# awk '/^C/{print $0}' data5.txt
Charlie 22 Student
匹配操作符
[root@localhost ~]# cat data5.txt
Alice 25 Engineer
Bob 30 Doctor
Charlie 22 Student
David 35 Lawyer
Eve 28 Artist[root@localhost ~]# awk '$3 ~ /i/{print $0}' data5.txt
Alice 25 Engineer
Eve 28 Artist[root@localhost ~]# awk '$3 !~ /i/{print $0}' data5.txt
Bob 30 Doctor
Charlie 22 Student
David 35 Lawyer
數學表達式
除了正則表達式,你也可以在匹配模式中用數學表達式。這個功能在匹配數據字段中的數字值時非常方便。
可以使用常見的數學比較表達式:
x == y | 值 x 等于 y |
x <= y | 值 x 小于等于 y |
x < y | 值 x 小于 y |
x >= y | 值 x 大于等于 y |
x > y | 值 x 大于 y |
[root@localhost ~]# cat data5.txt
Alice 25 Engineer
Bob 30 Doctor
Charlie 22 Student
David 35 Lawyer
Eve 28 Artist[root@localhost ~]# awk '$2>=25{print $0}' data5.txt
Alice 25 Engineer
Bob 30 Doctor
David 35 Lawyer
Eve 28 Artist[root@localhost ~]# awk 'BEGIN{FS=":"}$1=="root"{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash[root@localhost ~]# awk 'BEGIN{FS=":"}$1>="q"{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
tss:x:59:59:Account used for TPM access:/:/usr/sbin/nologin
systemd-coredump:x:999:997:systemd Core Dumper:/:/sbin/nologin
sssd:x:997:995:User for sssd:/:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/usr/share/empty.sshd:/usr/sbin/nologin
redhat:x:1000:1000:redhat:/home/redhat:/bin/bash
rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin
rpcuser:x:29:29:RPC Service User:/var/lib/nfs:/sbin/nologin
結構化命令
if語句
[root@localhost ~]# cat data6.txt
10
5
13
50
34
[root@localhost ~]# awk '{if($1 > 20) print $1}' data6.txt
50
34
[root@localhost ~]# cat script4.awk
{if($1%400==0){print $1 " is Leap Year"}else if($1%4==0 && $1%100!=0)print $1 " is Leap Year"elseprint $1 " not is Leap Year"}
[root@localhost ~]# cat data7.txt
2014
2020
2017
2019
2024
2026
1900
[root@localhost ~]# awk -f script4.awk data7.txt
2014 not is Leap Year
2020 is Leap Year
2017 not is Leap Year
2019 not is Leap Year
2024 is Leap Year
2026 not is Leap Year
1900 not is Leap Year
while語句
[root@localhost ~]# cat data8.txt
130 120 135
160 113 140
145 170 215
[root@localhost ~]# cat script5.awk
BEGIN{sum=0
}
{s=0i=1while(i<NF){s+=$ii++}print NR "‘sum: " ssum+=s
}
END{print "sum: " sum
}
[root@localhost ~]# awk -f script5.awk data8.txt
1‘sum: 250
2‘sum: 273
3‘sum: 315
sum: 838
?awk編程語言支持在while循環中使用break語句和continue語句,允許你從循環中跳出。
[root@localhost ~]# cat script5.awk
BEGIN{sum=0
}
{s=0i=1while(i<NF){s+=$ii++if(i==2)break}print NR "‘sum: " ssum+=s
}
END{print "sum: " sum
}
[root@localhost ~]# awk -f script5.awk data8.txt
1‘sum: 130
2‘sum: 160
3‘sum: 145
sum: 435
do-while語句
[root@localhost ~]# cat data8.txt
130 120 135
160 113 140
145 170 215
[root@localhost ~]# cat script6.awk
BEGIN{sum=0
}
{s=0i=1do{s+=$ii++}while(i<NF)print NR "‘sum: " ssum+=s
}
END{print "sum: " sum
}
[root@localhost ~]# awk -f script6.awk data8.txt
1‘sum: 250
2‘sum: 273
3‘sum: 315
sum: 838
for語句
[root@localhost ~]# cat data8.txt
130 120 135
160 113 140
145 170 215
[root@localhost ~]# cat script7.awk
BEGIN{sum=0
}
{s=0for(i=1;i<NF;i++){s+=$i}print NR "‘sum: " ssum+=s
}
END{print "sum: " sum
}
[root@localhost ~]# awk -f script7.awk data8.txt
1‘sum: 250
2‘sum: 273
3‘sum: 315
sum: 838
內建函數
數學函數
函數 | 描述 |
atan2(x, y) | x/y 的反正切, x 和 y 以弧度為單位 |
cos(x) | x 的余弦, x 以弧度為單位 |
exp(x) | x 的指數函數 |
int(x) | x 的整數部分,取靠近零一側的值 |
log(x) | x 的自然對數 |
rand( ) | 比 0 大比 1 小的隨機浮點值(不包括0或1) |
sin(x) | x 的正弦, x 以弧度為單位 |
sqrt(x) | x 的平方根 |
srand(x) | 為計算隨機數指定一個種子值 |
字符串函數
函數 | 描述 |
asort(s [,d]) | 將數組 s 按數據元素值排序。索引值會被替換成表示新的排序順序的連續數字。另外, 如果指定了d ,則排序后的數組會存儲在數組 d 中 |
asorti(s [,d]) | 將數組 s 按索引值排序。生成的數組會將索引值作為數據元素值,用連續數字索引來表明排序順序。另外如果指定了d ,排序后的數組會存儲在數組d 中 |
gensub(r, s, h [, t]) | 查找變量 $0 或目標字符串 t (如果提供了的話)來匹配正則表達式r 。如果 h 是一個以 g或G 開頭的字符串,就用 s 替換掉匹配的文本。如果 h 是一個數字,它表示要替換掉第h處r 匹配的地方 |
gsub(r, s [,t]) | 查找變量 $0 或目標字符串 t (如果提供了的話)來匹配正則表達式r 。如果找到了,就 全部替換成字符串 s |
index(s, t) | 返回字符串 t 在字符串 s 中的索引值,如果沒找到的話返回 0 |
length([s]) | 返回字符串 s 的長度;如果沒有指定的話,返回 $0 的長度 |
match(s, r [,a]) | 返回字符串 s 中正則表達式 r 出現位置的索引。如果指定了數組a ,它會存儲 s 中匹配正則表達式的那部分 |
split(s, a [,r]) | 將 s 用 FS 字符或正則表達式 r (如果指定了的話)分開放到數組a 中。返回字段的總數 |
sprintf(format,variables) | 用提供的 format 和 variables 返回一個類似于 printf 輸出的字符串 |
sub(r, s [,t]) | 在變量 $0 或目標字符串 t 中查找正則表達式 r 的匹配。如果找到了,就用字符串s 替換 掉第一處匹配 |
substr(s, i [,n]) | 返回 s 中從索引值 i 開始的 n 個字符組成的子字符串。如果未提供n ,則返回 s 剩下的部 分 |
tolower(s) | 將 s 中的所有字符轉換成小寫 |
toupper(s) | 將 s 中的所有字符轉換成大寫 |
[root@localhost ~]# awk '{print length($1)}'
hello
5
red
3[root@localhost ~]# cat script8.awk
BEGIN{a[0] = 45a[1] = 12a[2] = 34a[3] = 5asort(a)for(i in a){print a[i]}
}
[root@localhost ~]# awk -f script8.awk
5
12
34
45//split可以很方便的將字段放進數組中[root@localhost ~]# cat script9.awk
BEGIN{FS=":"
}
{split($0,var)print var[1],var[NF]
}
[root@localhost ~]# head -3 /etc/passwd | awk -f script9.awk
root /bin/bash
bin /sbin/nologin
daemon /sbin/nologin
時間函數
函數 | 描述 |
mktime(datespec) | 將一個按 YYYY MM DD HH MM SS [DST] 格式指定的日期轉換成時間戳值 |
strftime(format[,timestamp]) | 將當前時間的時間戳或 timestamp (如果提供了的話)轉化格式化日期(采用shell函數date() 的格式) |
systime( ) | 返回當前時間的時間戳 |
?下面是在awk程序中使用時間函數的例子。
[root@localhost ~]# cat script10.awk
{date=systime()print strftime("%Y %T",date)
}
[root@localhost ~]# awk -f script10.awk 2025 21:23:542025 21:23:562025 21:23:57
自定義函數
自定義函數基本格式
function name([variables])
{
statements
return value
}
?在定義函數時,它必須出現在所有代碼塊之前(包括BEGIN代碼塊)。
[root@localhost ~]# cat script12.awk
function leap(year){if(year%400==0){print year " is Leap Year"}else if(year%4==0 && year%100!=0)print year " is Leap Year"elseprint year " not is Leap Year"}
BEGIN{for(i=2025;i<=2050;i++){leap(i)}
}[root@localhost ~]# awk -f script12.awk
2025 not is Leap Year
2026 not is Leap Year
2027 not is Leap Year
2028 is Leap Year
2029 not is Leap Year
2030 not is Leap Year
2031 not is Leap Year
2032 is Leap Year
2033 not is Leap Year
2034 not is Leap Year
2035 not is Leap Year
2036 is Leap Year
2037 not is Leap Year
2038 not is Leap Year
2039 not is Leap Year
2040 is Leap Year
2041 not is Leap Year
2042 not is Leap Year
2043 not is Leap Year
2044 is Leap Year
2045 not is Leap Year
2046 not is Leap Year
2047 not is Leap Year
2048 is Leap Year
2049 not is Leap Year
2050 not is Leap Year