文章目錄
awk的工作模式
語法格式
第一種形式
awk 'BEGIN{}pattern{commands}END{}' file_name
- BEGIN{}表示文本開始之前,進行{}內的操作
- END{}表示文本開始以後,進行{}內的操作
- pattern 表示對那些行進行操作,不寫則默認是所有行
- {commands}對行進行的操作,可以寫多個命令
第二種形式
cat file_name | awk 'BEGIN{}pattern{commands}END{}'
awk的內置變量
n內置變量 | 含義 |
---|---|
$0 | 整行內容 |
n | 當前行的第1-n個字段 |
NF | 當前行的字段個數,即多少列 |
NR | 當前行的行號,從1開始計數 |
FNR | 多個文件處理時,每個文件行號單獨計數,都是從0開始 |
FS | 輸入字段分隔符。不指定默認以空格或tab分割 |
RS | 輸入行分割符,默認回車換行 |
OFS | 輸出字段分隔符,默認空格 |
ORS | 輸出行分隔符。默認回車 |
FILENAME | 當前輸入的文件名 |
ARGC | 命令行參數個數 |
ARGV | 命令行參數數組 |
示例
- list內容
java:python:scala
hadoop:spark:flume
jake:mike:coco
awk 'BEGIN{FS=":"}{print $1}' list # BEGIN中指定分隔符爲:
awk 'BEGIN{FS=":"}{print NR}' list # 顯示行號
awk 'BEGIN{FS=":"}{print NF}' list # 顯示每行的列數
awk 'BEGIN{FS=":"}{print NF}' list list #行號爲連續顯示
awk 'BEGIN{FS=":"}{print FNR}' list list1 # 每個文件是單獨計算行號
awk 'BEGIN{FS=":"}{print $NF}' list # 輸出最後一列
格式化輸出printf
格式說明符
格式符 | 含義 |
---|---|
%s | 打印字符串 |
%d | 打印十進制數 |
修飾符
修飾符 | 含義 |
---|---|
- | 左對齊 |
+ | 右對齊 |
+ | 顯示8進制在前面加0,顯示16進制在前面加0x |
示例
以字符串格式化打印 /etc/passwd中的第七個字段,並且以":" 作爲分隔符
awk 'BEGIN{FS=":"} {printf "%s:",$7}' /etc/passwd
以10進制打印/etc/passwd中第三個字段,以":"作爲分隔
awk 'BEGIN{FS=":"} {printf "%10d\n",$3}' /etc/passwd # 右對齊10個字符
浮點數打印
awk 'BEGIN{FS=":"} {printf "%0.2f\n",$3}' /etc/passwd # 浮點數打印 保留兩位小數
awk模式匹配的兩種方法
第一種模式匹配:RegExp正則表達式匹配
示例
匹配/etc/passwd文件中含有root字符串的所有行
awk 'BEGIN{FS=":"}/root/{print $0}' /etc/passwd
匹配/etc/passwd文件中以yarn開頭的所有行
awk 'BEGIN{FS=":"}/^yarn/{print $0}' /etc/passwd
第二種模式匹配:關係運算匹配
- 支持 常用關係運算符 > < >= <= == !=
- 還支持 ~:匹配正則表達式
- !~不匹配正則表達式
示例
匹配/etc/passwd中第三個字段小於50的行
awk 'BEGIN{FS=":"}$3<50{print $0}' /etc/passwd
匹配第三個字段包含3個或3個以上的數字信息的所有行
awk 'BEGIN{FS=":"}$3~/[0-9]{3,}/{print $0}' /etc/passwd # /[0-9]{3,}/ 固定寫法
布爾運算符匹配
|| 或
&& 與
! 非
匹配/etc/passwd文件中包含hdfs或yarn的所有行信息
awk 'BEGIN{FS=":"}$1=="hdfs" || $1=="yarn" {print $0}' /etc/passwd
awk中表達式的用法
符號 | 含義 |
---|---|
+ | 加 |
* | 乘法 |
- | 減 |
/ | 除法 |
% | 取模 |
^或** | 乘方 |
++x | 先加1 |
x++ | 後加1 |
統計/etc/services中空白行的數量
awk '/^$/{sum++} END{print sum}' /etc/services # /^$/ 表示空白行
統計學生分數平均值
學生課程文件如下:
Allen 80 90 96 98
mike 93 98 92 91
zhang 78 76 87 92
awk 'BEGIN{printf "%-8s%-8s%-8s%-8s%-8s%-8s\n","name","math","english","chinese","history","avg"} {total=$2+$3+$4+$5;avg=total/4;printf "%-8s%-8d%-8d%-8d%-8d%-0.2f\n",$1,$2,$3,$4,$5,avg}' stu.txt
awk動作中的條件及循環語句
條件語句
if(條件表達式)
動作1
else if
動作2
else
動作3
示例
只打印/etc/passwd/中第3個字段的數值在50-100範圍內的行
awk 'BEGIN{FS=":"}{if($3<100 && $3>50) print($0)}' /etc/passwd
將命令寫到文件中,並且執行 main.awk
BEGIN{FS=":"}{if($4<100 && $3>50) print($0)}
執行如下語句
awk -f main.awk /etc/passwd
循環語句
while循環
do while
for循環,語法格式和c語言一致。
示例
計算1+2+3+…100的和,使用while、do while、for循環三種方式實現
# for循環
BEGIN{
for(i=0;i<=100;i++)
{
sum+=i
}
print sum
}
# while
BEGIN{
while(i<=100){
sum+=i
i++
}
print sum
}
#do while
BEGIN{
i=0
do{
sum+=i
i++
}while(i<=100)
print sum
}
awk中的字符串函數
常用字符串函數
函數名 | 解釋 | 函數返回值 |
---|---|---|
length(str) | 字符串長度 | 整數長度值 |
index(str1,str2) | 在str1中查找str2的位置 | 返回位置索引,從1計數 |
tolower(str) | 轉成小寫 | 轉化後的字符串 |
toupper(str) | 轉成大寫 | 轉化後的字符串 |
substr(str,m,n) | 從str的m個字符開始,截取n位 | 截取後的子串 |
split(str,arr,fs) | 按照fs切割字符串,結果保存arr | 切割後子串的個數 |
match(str,RE) | 在str中按照RE查找,返回位置 | 返回索引位置 |
sub(RE,RepStr,str) | 在str中搜索符合RE的字符串,將其替換爲RepStr,只替換一個 | 替換的個數 |
gsub(RE,RepStr,str) | 在str中搜索符合RE的字符串,將其替換爲RepStr,替換所有 | 替換的個數 |
示例
統計/etc/passwd中每行,每個字段的長度
BEGIN{
FS=":"
}
{ i=0
while(i<=NF)
{
if(i==NF){
printf "%d",$i
}
else{
printf "%d:",$i
}
i++
}
print ""
}
搜索字符串"I have s dream" 中出現"ea"子串的位置
# 使用index
awk 'BEGIN{str="I have s dream";location=index(str,"ea");print location}'
# 使用match
awk 'BEGIN{str="I have s dream";location=match(str,"ea");print location}'
字符串大小寫轉換
awk 'BEGIN{str="I have s dream";print tolower(str)}'
awk 'BEGIN{str="I have s dream";print toupper(str)}'
字符串分割
awk 'BEGIN{str="I have s dream";split(str,arr," ");for(i in arr) print arr[i]}'
截取子串
awk 'BEGIN{str="I have s dream"; print substr(str,4,5)}'
awk 'BEGIN{str="I have s dream"; print substr(str,4)}' # 第四位開始
字符串替換
# 將123替換爲$ 符號。sub返回的個數,直接修改str
awk 'BEGIN{str="my 123 dream"; sub(/[0-9]+/,"$",str);print str}'
awk選項總結
選項 | 解釋 |
---|---|
-v | 參數傳遞 |
-f | 指定腳本文件 |
-F | 指定分隔符 |
-V | 查看awk版本號 |
傳遞參數
num1=20
var="hello world"
awk -v num2="$num1" -v var1="$var" 'BEGIN{print num2,var1}'
awk中的數組
shell中數組用法
定義
array=("Allen" "Mike" "Jick") # 空格分割
數組操作
# 打印元素
echo ${array[2]}
# 打印數組元素個數
echo ${#array[@]}
# 打印數組元素長度
echo ${#array[3]}
# 給元素複製
array[3]="Li"
# 刪除元素
unset array[0] # 被刪掉後 下標不變
# 分片訪問
echo ${array[@]:1:3}
# 元素內容替換
${array[@]/e/E} # 只替換第一個e
${array[@]//e/E} # 替換所有的e
數組遍歷
for a in ${array[@]}
do
echo $a
done
awk中的數組
在awk中,使用數組時,不僅可以使用1,2,3…作爲數組下標,還可以使用字符串作爲下標
使用數字作爲下標
str="Allen Jerry Mike"
split(str,array)
for(i=1;i<=length(array);i++)
print array[i]
使用字符串作爲下標
array["var1"]="Jin"
array["var2"]="Hao"
array["var3"]="Fang"
for(a in array)
print array[a]
awk數組示例
統計tcp鏈接狀態個數
netstat -an | grep tcp | awk '{a[$6]++}END{for(i in a) print i,a[i]}'
計算橫向數據總合,計算縱向數據總和
- 數據
allen 80 90 87 91
mike 99 100 100 80
kobe 99 98 99 100 - 腳本
BEGIN{
printf "%-10s%-10s%-10s%-10s%-10s\n","name","yuwen","math","english","total"
}
{
total=$2+$3+$4
yuwen_sum+=$2 # 列之間的數累加
math_sum+=$3
enlish_sum+=$4
printf "%-10s%-10s%-10s%-10s%-10s\n",$1,$2,$3,$4,total
}
END{
printf "%-10s%-10s%-10s%-10s%-10s\n","",yuwen_sum,math_sum,enlish_sum,""
}
awk中getline用法
getline可以實現同時讀取兩個文件進行操作
示例
- file1
A 1
B 2
C 3
- file2
A
C
- 腳本
BEGIN{
while(getline<"file1"){a[$1]=$2} # 將file1中加載到數組中
}
{
if($1 in a) print $0 # 如果file2中的$1在數組a中 則打印
}
END{
}