awk 是一個文本處理工具,一般用於處理數據並生成結果報告。其命名源於三位創始人姓氏首字母:Alfred Aho、Peter Weinberger、Brian Kernighan。
語法:docker
awk [options] 'BEGIN{} pattern {commands} END{}' file
stdout | awk [options] 'BEGIN{} pattern {commands} END{}'
說明:shell
options
選項BEGIN{}
正式處理數據以前執行pattern
匹配模式{commands;...}
處理命令,可能多行END{}
處理完全部匹配數據後執行<!-- more -->數組
變量名 | 說明 |
---|---|
$0 |
整行內容 |
$1-$n |
當前行的第 1 - n 個字段(列) |
NF |
Number Field,當前行字段個數(多少列) |
NR |
Number Row,當前行的行號,從 1 開始計數 |
FNR |
File Number Row,多文件處理時,每一個文件行號單獨計數,都是從 0 開始 |
FS |
Field Separator,輸入字段分隔符(默認空格或 tab 鍵) |
RS |
Row Separator,輸入行分隔符(默認回車換行) |
OFS |
Output Field Separator,輸出字段分隔符(默認空格) |
ORS |
Output Row Separator,輸出行分隔符(默認回車換行) |
FILENAME |
當前輸入的文件名字 |
ARGC |
命令行參數個數 |
ARGV |
命令行參數數組 |
示例:bash
# 以 : 分隔,輸出第 1 列 ➜ awk 'BEGIN{FS=":"} {print $1}' /etc/passwd # 以 -- 分隔成行,以 : 分隔成列,輸出第 一、2 列 ➜ awk 'BEGIN{FS=":";RS="--"} {print $1,$2}' /etc/passwd # 以 : 分隔列,輸出最後一列,由於 NF 變量是總列數 ➜ awk 'BEGIN{FS=":"} {print $NF}' /etc/passwd
格式符 | 說明 | 修飾符 | 說明 |
---|---|---|---|
%s |
字符串 | - |
左對齊 |
%d |
十進制 | + |
右對齊 |
%f |
浮點數 | # |
八進制前面加 0,十六進制前面加 0x |
%x |
十六進制 | ||
%o |
八進制 | ||
%e |
科學計數法 | ||
%c |
單個字符的 ASCII 碼 |
示例:函數
# printf "%+20s %-20s\n",$1,$7 # - 左對齊;+ 右對齊 # 20 列寬,不足則補空 # s 打印字符串 # .3f 打印保留 3 位數的浮點數 ➜ awk 'BEGIN{FS=":";OFS="-"}{printf "%+20s %20.3f %-20s\n",$1,$3,$7}' /etc/passwd root 0.000 /bin/bash bin 1.000 /sbin/nologin daemon 2.000 /sbin/nologin adm 3.000 /sbin/nologin lp 4.000 /sbin/nologin
RegExp
:/patern/
關係運算
:<
、>
、<=
、>=
、==
、!=
、~
正則匹配、!~
非正則匹配、&&
與、||
或、!
非示例:工具
# 打印以 root 開頭的行 ➜ awk 'BEGIN{FS=":"} /^root/ {print $0}' /etc/passwd root:x:0:0:root:/root:/bin/bash # 打印第 3 列大於 1000 的行 ➜ awk 'BEGIN{FS=":"} $3>1000 {print $0}' /etc/passwd nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin # 打印第 7 列是 /sbin/nologin 的行 ➜ awk 'BEGIN{FS=":"} $7=="/sbin/nologin" {print $0}' /etc/passwd bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin # 打印第 7 列以 nologin 結尾的行 ➜ awk 'BEGIN{FS=":"} $7~/.*nologin$/ {print $0}' /etc/passwd bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin # 打印第 3 列大於 500,而且第 7 列以 nologin 結尾的行 ➜ awk 'BEGIN{FS=":"} $3>500 && $7~/.*nologin$/ {print $0}' /etc/passwd chrony:x:997:995::/var/lib/chrony:/sbin/nologin dockerroot:x:996:993:Docker User:/var/lib/docker:/sbin/nologin
示例:this
# 數學計算 ➜ awk 'BEGIN{x=10;y=2; print x+y}' 12 ➜ awk 'BEGIN{x=10;y=2; print x*y}' 20 ➜ awk 'BEGIN{x=10;y=2; print x^y}' 100 ➜ awk 'BEGIN{x=10;y=2; print x**y}' 100 ➜ awk 'BEGIN{x=10;y=x++; print x,y}' 11 10 ➜ awk 'BEGIN{x=10;y=++x; print x,y}' 11 11 # 打印空行行號、統計空行數量 ➜ awk 'BEGIN{idx=0;} /^$/ {idx++; print NR} END{print idx;}' /etc/passwd
語法:命令行
# 條件判斷 if(condition1) { # do something } else if(condition2) { # do something } else { # do something } # 循環 while(condition) { #do something } do # do something while(condition) for(i=0;i<10;i++) { # do something }
示例:code
# 若是第 3 列小於 10 而且第 7 列是 /sbin/nologin 的行打印 this is if # 若是第 3 列大於 500 的打印 this is else if # 不然打印 this is else ➜ awk 'BEGIN{FS=":"} { if($3<10 && $7="/sbin/nologin") {print "this is if"} else if($3>500) {print "this is else if"} else {print "this is else"}}' /etc/passwd this is if this is if this is else this is else if this is else # 計算 1-10 相加的結果 # 注意:變量不須要提早聲明 ➜ awk 'BEGIN{ while(i<10) { sum+=i; i++}; print sum}' 45 ➜ awk 'BEGIN{do { sum+=i; i++; } while(i<10); print sum}' 45 ➜ awk 'BEGIN{ for(i=0;i<10;i++) { sum+=i; }; print sum}' 45
函數名 | 說明 | 返回值 |
---|---|---|
length(str) |
計算字符串長度 | 整數長度值 |
index(str,sub_str) |
在 str 中查找 sub_str 的位置 | 位置索引,從 1 計數 |
tolower(str) |
轉小寫 | 轉換後的小寫字符串 |
toupper(str) |
轉大些 | 轉換後的大寫字符串 |
substr(str,start,length) |
從 str 第 start 個字符開始,截取 length 位 | 截取後到子串 |
split(str,arr,fs) |
按 fs 拆分字符串,結果保存到 arr | 拆分後子串的個數 |
match(str,reg) |
在 str 中按 reg 查找,返回位置 | 索引位置 |
sub(reg,new_sub_str,str) |
在 str 中搜索符合 reg 的子串,將其替換爲 new_sub_str,只替換第一個 | 替換的個數 |
gsub(reg,new_sub_str,str) |
相似 sub ,替換全部 |
替換的個數 |
示例:索引
# sub(/oo/,"11",$1) 返回替換的個數;後面的 $1 爲替換後的值 ➜ awk 'BEGIN{FS=":"} { print length($1),toupper($1),substr($1,0,2),sub(/oo/,"11",$1),$1}' /etc/passwd 4 ROOT ro 1 r11t 3 BIN bi 0 bin 6 DAEMON da 0 daemon 4 SYNC sy 0 sync # 數組下標從 1 開始 ➜ awk 'BEGIN{str="Shell;Python;C;C++;Java;PHP"; split(str,arr,";"); print arr[2]}' Python ➜ awk 'BEGIN{str="Shell;Python;C;C++;Java;PHP"; split(str,arr,";"); for(i in arr) { print arr[i]; }}' C++ Java PHP Shell Python C
-v
參數傳遞-f
指定腳本文件-v
指定分隔符-V
查看 awk 版本示例:
# 引入外部變量 ➜ var1=10 ➜ var2="hello awk" ➜ awk -v var1="$var1" -v var2="$var2" 'BEGIN{print var1,var2}' 10 hello awk # 把全部操做抽離到一個獨立文件 # 建議:複雜操做優先使用這種方式,更易於程序理解和管理 ➜ touch script.awk BEGIN{ FS=":" } { if($3<10 && $7="/sbin/nologin") { print "this is if" } else if($3>500) { print "this is else if" } else { print "this is else" } } ➜ awk -f script.awk /etc/passwd # -F: 至關於 BEGIN{FS=":"} $ awk -F: '{print $1}' pwd root bin daemon
shell 中的數組操做以下:
操做 | 示例 | 輸出 |
---|---|---|
定義一個數組 | arr=("Python" "PHP" "Java" "Go" "Rust") |
|
某個數組元素(下標從 0 開始) | echo ${arr[2]} |
Java |
數組元素個數 | echo ${#arr[@]} |
5 |
某個元素的長度 | echo ${#arr[0]} |
6 |
修改元素值 | arr[2]="JAVA" |
|
刪除數組元素 | unset arr[1] |
|
打印全部數組元素) | echo ${arr[@]} |
Python JAVA Go Rust |
分片訪問 | echo ${arr[@]:0:2} |
Python JAVA |
數組元素替換(找到的第一個) | echo ${arr[@]/A/a} |
Python JaVA Go Rust |
數組元素替換(全部) | echo ${arr[@]//A/a} |
Python JaVa Go Rust |
數組遍歷 | for a in ${arr[*]}; do echo $a; done |
而 awk 中數組的使用略有不一樣,它使用 關聯數組提供數組功能,即數組的索引能夠是 數字或 任意字符串。
語法示例:
# 定義 # 語法:array_name[index]=value ➜ awk 'BEGIN{arr[0]=0; arr["second"]="2"; print arr[0],arr["second"];}' 0 2 # 數組元素參與計算 ➜ awk 'BEGIN{arr[0]=0; arr["second"]="2"; print arr[0]+3,arr["second"];}' 3 2 # 刪除數組元素 # 語法:delete array_name[index] ➜ awk 'BEGIN{arr[0]=0;arr["second"]="2"; delete arr["second"]; print arr["second"];}' # 遍歷數組 # 方式一:for ... in 是無序輸出 ➜ awk 'BEGIN{str="Python Rust PHP Go"; arrLen=split(str,arr," "); for(i in arr){ print i,arr[i] }}' 4 Go 1 Python 2 Rust 3 PHP # 方式二:for(i=1;i<=len;i++) { ... } 有序輸出 ➜ awk 'BEGIN{str="Python Rust PHP Go"; arrLen=split(str,arr," "); for(i=1;i<=arrLen;i++){ print i,arr[i] }}' 1 Rust 2 Go 3 Python 4 PHP