awk 程式設計#
awk 運算符#
算術運算符#
運算符 | 描述 |
---|---|
+ - * / % | 加 減 乘 除 取餘 |
^ ** | 求幂 |
++ -- | 自增 自減 (可作為前綴或後綴) |
赋值运算符#
运算符 | 描述 |
---|---|
= += -= *= /= %= ^= **= | 赋值语句(a+=b 等价于 a=a+b,其他类似) |
關係運算符#
運算符 | 描述 |
---|---|
> < >= <= != == | 比較語句(成立返回真,不成立返回假) |
邏輯運算符#
運算符 | 描述 |
---|---|
|| | 邏輯或(有真則真) |
&& | 邏輯與(有假則假) |
! | 邏輯非(真變假,假變真) |
正則運算符#
運算符 | 描述 |
---|---|
~ | 匹配正則表達式 |
!~ | 不匹配正則表達式 |
其他運算符#
運算符 | 描述 |
---|---|
$ | 欄位引用 |
空格 | 字串連接符 |
in | 陣列成員迭代符(一般和 for 循環一起,用於遍歷陣列) |
? : | 三目運算符(和 C 語言一樣: 表達式 ? 語句1 : 語句2 表達式成立,執行語句 1,否則執行語句 2) |
awk 流程控制語句#
條件判斷語句#
# if
if(表達式)
語句
# if-else
if(表達式)
語句1
else
語句2
# if-else-if
if(表達式)
語句1
else if (表達式2)
語句2
else
語句3
awk 分支結構允許嵌套,為了方便判斷和閱讀,可以將多個語句用 {} 括起來
循環語句#
- 三大循環語句
# while循環
while(表達式){
語句
}
# for循環
# 格式1
for(初始變數;循環判斷語句;循環遍歷遞增/遞減語句){
語句
}
# 格式2
for(變數 in 陣列){
語句
}
# do-while循環
do{
語句
} while(條件)
循環流程改變語句:
break;
退出循環continue;
跳過本次循環exit status_code;
exit
語句用於停止腳本的執行(若有END
則是轉移到END
),接受一個整數參數作為awk
進程的退出狀態碼,如未提供參數,則默認為 0($?
可以查看)
awk 陣列#
陣列是 awk 的靈魂,處理文本中常常會用到陣列處理
awk
陣列特性:
awk
陣列的下標可以是數字,也可以是字串,因此,awk
中陣列是關聯陣列- 在內部,
awk
陣列的索引全都是字串,即使是數值索引在使用時內部也會轉換成字串 awk
的陣列元素的順序和元素插入時的順序不一定相同awk
中的陣列不必提前聲明,也不用聲明大小- 陣列元素會根據上下文使用 0 或空字串來初始化
創建(添加、修改)陣列#
語法:陣列名[下標] = 值
- 給陣列添加 / 修改元素的語法和創建陣列一樣
訪問陣列元素#
語法:陣列名[下標]
刪除陣列元素#
語法:delete 陣列名[下標]
- 刪除不存在的元素不會報錯
delete 陣列名
可以直接刪除陣列所有元素
陣列相關函數#
-
length(arr)
獲取陣列長度 -
asort(arr)
對陣列進行排序,並返回陣列長度 -
split(str,arr,sep)
分割字串為陣列,並返回陣列長度生成的 awk 陣列下標從 1 開始,和 C 語言陣列不一樣
[root@localhost ~]# awk 'BEGIN{str="a,b,c,d";len=split(str,arr,",");print len,length(arr),asort(arr),arr[1]}'
4 4 4 a
遍歷陣列#
# 方式1
[root@localhost ~]# awk 'BEGIN{
str="a,b,c,d";
len=split(str,arr,",");
for(i in arr){
print i,arr[i];
}
}'
1 a
2 b
3 c
4 d
# 方式2 (awk陣列是關聯陣列,該方式可以保證有序遍歷)
[root@localhost ~]# awk 'BEGIN{
str="a,b,c,d";
len=split(str,arr,",");
for(i=1;i<=len;i++){
print i,arr[i];
}
}'
1 a
2 b
3 c
4 d
# 判斷陣列中是否包含某個key
if(key in arr)
# 檢測arr是否是陣列
isarray(arr) 如果arr是陣列,返回1,否則返回0
typeof(arr) 返回數據類型,如果arr是陣列,返回 'array'
多維陣列#
- awk 只支持一維陣列,我們可以使用一維陣列來模擬多維陣列
# 有如下 3*3 的二維陣列arr:
1 2 3
4 5 6
7 8 9
在C語言中,arr[0][0] = 100;在awk中,我們可以令arr[0,0] = 100,以此類推:arr[0,1]、arr[0,2]...arr[3,3];
實際上,0,1 0,2 3,3 只是一个字符串索引
awk 內置函數#
數學函數#
函數 | 描述 |
---|---|
sin(expr) | 返回 expr 的正弦值 |
cos(expr) | 返回 expr 的余弦值 |
atan2(y,x) | 返回 y/x 的反切值 |
log(expr) | 返回 expr 的自然對數 |
exp(expr) | 返回以 e 為底,expr 的指數值 |
sqrt(expr) | 返回 expr 的平方根 |
int(expr) | 返回 expr 截斷至整數的值 |
rand() | 返回任意數字 n,其中 0<=n<1 |
srand([expr]) | 把 rand 函數的種子值設置為 expr 參數的值,如果省略參數,則使用某天的時間 |
示例#
# 獲取0-99之間的隨機整數
[root@localhost ~]# awk 'BEGIN{srand();randint=int(100*rand());print randint}'
字串函數#
函數 | 描述 |
---|---|
asort(arr [, d ]) | 按 ASCII 字符順序對陣列 arr 的值進行排序 |
asorti(arr [, d]) | 按 ASCII 字符順序對陣列 arr 的鍵進行排序 |
gsub(regexp, sub, str) | 在一個字串中查找指定的模式匹配的全部字串,找到之後都替換為另一個字串 |
sub(search, sub, str) | 在一個字串中查找指定的字串,找到之後則替換為另一個字串。只會替換一次 |
index(str, sub) | 查找一個字串在另一個字串中的位置。如果找到則返回找到的位置,否則返回 0 |
length(str) | 返回一個字串的長度 |
match(str, regexp) | 查找匹配模式的第一個最長子串位置。如果沒找到則返回 0,找到則返回最長子串的開始位置 |
split(str, arr, regexp) | 把一個字串根據給定的模式分割成多個子串。如果沒有傳遞模式則會使用變數 FS 的值 |
printf(format, expr-list) | 根據給定的字串格式和傳遞的變數構造字串並輸出到標準輸出 |
strtonum(str) | 用於檢查一個字串是否數字並將它轉換為十進制數字 |
substr(str, start, len) | 用於返回字串 str 中的從 start 的位置開始,長度為 len 的子串 |
tolower(str) | 用於將指定的字串中的大寫字母轉換為小寫字母 |
toupper(str) | 用於將指定的字串中的小寫字母轉換為大寫字母 |
示例#
# asort(arr[,d]) arr-->陣列 d-->陣列,如果傳了該參數,就不會修改arr,而是把arr中所有元素拷貝到d,然後對d進行排序
[root@localhost ~]# awk 'BEGIN{
arr[11]=800;
arr[22]=200;
arr[33]=300;
arr[44]=100;
for(i in arr){
print i,arr[i];
}
asort(arr);
print;
for(j in arr){
print j,arr[j];
}
}'
11 800
22 200
33 300
44 100
1 100
2 200
3 300
4 800
# asorti
[root@localhost ~]# awk 'BEGIN{
arr[11]=800;
arr[22]=200;
arr[33]=300;
arr[44]=100;
for(i in arr){
print i,arr[i];
}
asorti(arr);
print;
for(j in arr){
print j,arr[j];
}
}'
11 800
22 200
33 300
44 100
1 11
2 22
3 33
4 44
# gsub(regexp, sub, str)
[root@localhost ~]# awk 'BEGIN{
str="hello world";
gsub("[o|l]","*",str);
print str;
}'
he*** w*r*d
# sub(search, sub, str)
[root@localhost ~]# awk 'BEGIN{
str="hello world";
sub("[o|l]","*",str);
print str;
}'
he*lo world
# index(str, sub)
[root@localhost ~]# awk 'BEGIN{
str="hello world";
idx=index(str,"l");
print idx;
}'
3
# match(str, regexp)
[root@localhost ~]# awk 'BEGIN{
str="hello world hi haaaaaa";
idx=match(str,"h*");
print idx;
}'
1
# strtonum(str)
[root@localhost ~]# awk 'BEGIN{
str="01010";
res=strtonum(str);
print res;
}'
520
# substr(str, start, len)
[root@localhost ~]# awk 'BEGIN{
str="hello world";
res=substr(str,7,5);
print res;
}'
world
# tolower(str)
[root@localhost ~]# awk 'BEGIN{
str="HAHAHA";
res=tolower(str);
print res;
}'
hahaha
# tolupper(str)
[root@localhost ~]# awk 'BEGIN{
str="hello world";
res=toupper(str);
print res;
}'
HELLO WORLD
日期和時間函數#
函數 | 描述 |
---|---|
systime() | 返回當前時間戳 |
mktime(datespec) | 將指定格式的時間字串 (YYYY MM DD HH MM SS ) 轉換為時間戳 |
strftime([format [, timestamp]]) | 將一個時間戳格式的時間根據指定的時間格式化符轉成字串形式表示 |
示例#
# systime()
[root@localhost ~]# awk 'BEGIN{print systime()}'
1672448348
# mktime(datespec)
[root@localhost ~]# awk 'BEGIN{print mktime("2022 12 31 09 00 00")}'
1672448400
# strftime([format [, timestamp]])
[root@localhost ~]# awk 'BEGIN{print strftime("%c",systime())}'
Sat Dec 31 09:03:53 2022
格式化#
格式符 | 说明 |
---|---|
%a | 本地化的星期幾,例如 星期四 |
%A | 本地化的星期幾縮寫,例如 四 |
%b | 本地化的月份所寫,例如 5月 |
%B | 本地化的月份,例如 五月 |
%c | C 語言中的 %A %B %d %T %Y 的格式,例如 2019年05月30日 星期四 21時08分37秒 |
%C | 本年度的世紀部分。也就是四位數字年份的前兩位,例如 2019 年中的 20 |
%d | 當月中的第幾天,範圍為 01-31 ,例如 30 |
%D | 格式 %m/%d/%y 的簡寫,例如 05/30/19 |
%e | 當月中的第幾天,範圍為 1-31 ,如果小於 10 則在前面補空格,如 1 補全為 1 |
%F | ISO 8601 日期格式中的 %Y-%m-%d 的別名 |
%g | ISO 8601 日期格式中的周數除以 100 的值,範圍 00-99 例如 1993 年 1 月 1 日是 1992 年的第 53 周 |
%G | IOS 周數制下的完整年費,類似於四位數年份,例如 2019 |
%h | 格式 %b 的別名 |
%H | 24 小時制的當前時間的時,範圍為 00–23 |
%I | 12 小時制的當前時間的時,範圍為 01–12 |
%j | 一年中的第幾天,範圍為 001–366 |
%m | 當前時間的月,範圍為 01–12 |
%M | 當前時間的分,範圍為 00–59 |
%n | 換行符 \n |
%p | 本地化的 12 小時制時間格式中的 AM 或 PM ,也就是本地化的上午或下午表示形式 |
%r | 本地化的 12 小時制時間格式,類似於 C 語言中的 %I:%M:%S %p |
%R | 格式 %H:%M 的縮寫 |
%S | 當前時間的秒,範圍為 00-60 。60 主要考慮閏秒 |
%t | 製表符 \t |
%T | 格式 %H:%M:%S 的縮寫 |
%u | 一周中的第幾天,也就是星期幾,範圍為 1–7 。每周以星期一開始 |
%U | 一年中的第幾周,範圍為 00-53 。第一周從第一個星期日開始 |
%V | 一年中的第幾周,範圍為 01-53 。第一周從第一個星期一開始 |
%w | 一周中的第幾天,也就是星期幾,範圍為 0–6 。每周以星期日開始 |
%W | 一年中的第幾周,範圍為 00-53 。第一周從第一個星期一開始 |
%x | 本地化的完整日期表示,類似於 %A %B %d %Y ,例如 星期四 五月 30 2019 |
%X | 本地化的完整時間表示,類似於 C 語言中的 %T ,例如 07:06:05 |
%y | 兩位十進制年份,即取年份的後兩位,範圍為 00-99 ,比如 2019 則返回 19 |
%Y | 完整的 4 位十進制年份,例如 2019 |
%z | 以 +HHMM 格式的時區偏移。是 RFC 822 或 RFC 1036 日期格式中的組成部分。 |
%Z | 時區名稱或時區名稱縮寫。如果沒有時區則返回空字串 '' |
其他函數#
函數 | 描述 |
---|---|
close(expr) | 用於關閉已經打開的文件或管道 |
system(command) | 執行系統腳本命令,並返回腳本執行的退出狀態 |
getline | 讀取下一行 |
next | 處理下一行 |
nextfile | 處理下一個文件 |
示例#
# close(expr)
[root@localhost ~]# awk 'BEGIN{while("cat emp.txt" | getline){print $0}close("emp.txt")}'
# system(command)
[root@localhost ~]# awk 'BEGIN{system("ls -l")}'
# getline
[root@localhost ~]# awk '{getline;print}' emp.txt
002 李四 2000 10
004 赵六 2000 20
006 小丽 800 20
[root@localhost ~]# awk 'BEGIN{print "輸入:";getline name;print name}'
輸入:
123
123
# next
[root@localhost ~]# awk '{if($3<2000)next;print}' emp.txt
002 李四 2000 10
003 王五 3000 10
004 赵六 2000 20
# nextfile
[root@localhost ~]# awk '{if($3==2000) nextfile;print}' emp.txt file
001 張三 1000 10
xxx is a hanhan. ^_^
are you kidding?
I think ...
My phone number is 1872272****.
自定義函數#
- 函數定義
function 函數名(參數1, 參數2, ...) {
函數體
}
- 函數名必須以字母開始,可以由字母、數字、下劃線組成,不能使用保留字
- 函數體語句之間必須以分號分隔
- 函數可以有返回值,也可以沒有,如果需要返回值,則必須在大括號裡使用
return
關鍵字
- 函數調用
# 調用無參函數
fun_name
# 調用有參數的函數
fun_name(arg1[,arg2...])
# 調用有返回值的函數
var = fun_name([arg1...])
函數在
BEGIN
,主體
,END
中均可調用
示例#
# 無參數函數
[root@localhost ~]# awk 'BEGIN{
fun1()
}
function fun1(){
print "this is a function!"
}'
this is a function!
# 有參數函數
[root@localhost ~]# awk 'BEGIN{
fun2(10,20)
}
function fun2(num1,num2){
print "函數執行的結果是:"num1+num2
}'
函數執行的結果是:30
# 有返回值函數
[root@localhost ~]# awk 'BEGIN{
res = fun3(10,20);
print "num1+num2的和是:"res
}
function fun3(num1,num2){
return num1+num2
}'
num1+num2的和是:30