Linux基礎之Shell--Awk使用(一)
一、簡述
AWK程序可用於選擇文件中的特定記錄並對它們執行操作。對文本處理有非常好的支持。功能強大。
二、awk 基本使用
1. 運行一個簡單的awk 程序
[root@localhost Awk0-script]# awk 'BEGIN{print "Don\47t Panic!"}'
Don't Panic!
注意: ’ '(單引號),否則執行錯誤
2. 通過文件的方式運行
[root@localhost Awk0-script]# vim demo-01 #編輯 demo-01
BEGIN {print "Don't Panic!"}
[root@localhost Awk0-script]# awk -f demo-01 #運行 awk程序
Don't Panic!
3. 編寫可執行(Executable)的awk 程序
[root@localhost Awk0-script]# vim demo-02
[root@localhost Awk0-script]# chmod +x demo-02
############################################
#!/bin/awk -f
BEGIN {
print "Awk Executable Programs"
}
##########################################
[root@localhost Awk0-script]# ./demo-02
Awk Executable Programs
4. awk 程序的註釋 “#”
[root@localhost Awk0-script]# awk 'BEGIN { print "hello Awk" } # let's be cute'
> '
hello Awk
三、簡單的示例
1. 搜索文件中包含 ‘li’ 的記錄
[root@localhost Awk0-script]# awk '/li/ {print $0}' mail-list.txt
Amelia 555-5553 [email protected] F
Broderick 555-0542 [email protected] R
Julie 555-6699 [email protected] F
Samuel 555-3430 [email protected] A
2. 輸出7個0~100之間的隨機數
[root@localhost Awk0-script]# awk 'BEGIN { for (i = 1; i <= 7; i++)
> print int(101 * rand()) }'
24
29
85
15
59
19
81
3. 輸出所有記錄的字符數
[root@localhost Awk0-script]# awk '{print length($0) }' mail-list.txt
59
59
59
91
4. 統計當前文件使用的大小(bytes)
[root@localhost Awk0-script]# ll -l mail-list.txt
-rw-r--r--. 1 root root 752 Dec 8 16:28 mail-list.txt
# 查看單個文件所佔的字節數
[root@localhost Awk0-script]# ls -l mail-list.txt|awk '{print $5 " bytes"}'
752 bytes
#查看 當前目錄佔用的總字節數
[root@localhost Awk0-script]# ls -l ./ |awk 'BEGIN{print "The Directory Size(Bytes):"}{x+= $5}END{print x " bytes"}'
The Directory Size(Bytes):
1654 bytes
5. 打印當前文件的行數
[root@localhost Awk0-script]# awk 'END{print NR}' data.txt
17
6.輸出偶數行
[root@localhost Awk0-script]# awk 'NR % 2 == 0' data.txt #奇數行 awk 'NR % 2 == 1' data.txt
Feb 15 32 24 226
Apr 31 52 63 420
Jun 31 42 75 492
Aug 15 34 47 316
Oct 29 54 68 525
Dec 17 35 61 401
Jan 21 36 64 620
Mar 24 75 70 495
7.統計當前目錄下12月的文件佔用的字節:
ls -l | awk '$6 == "Dec" { sum += $5 }END { print sum }'
1654
8. 複雜的awk處理
[root@localhost Awk0-script]# echo a b | gawk 'BEGIN { FS = "" }
{
for (i = 1; i <= NF; i = i + 1)
print "Field", i, "is", $i,NF
}'
Field 1 is a 3
Field 2 is 3
Field 3 is b 3
9. 檢查當前系統用戶登錄的時間及登錄點
[root@localhost Awk0-script]# vim w_do.awk
BEGIN {
FIELDWIDTHs = "9 12 6 10 6 7 7 35"
printf "User LOGIN LOGIN_IP TIME \n"
printf "---------------------------------------------\n"
}
NR>2{
idle=$5
sub(/^ +/,idle)
if(idle== "")
idle=0
if(idle ~ /:/){
split(idle,t,":")
idle=t[1]*60+t[2]
}
if(idle~ /days/ )
idle*=24*60*60
printf "%2s %10s %15s %8s \n",$1,$2,$3,idle
}
[root@localhost Awk0-script]# w |awk -f w_do.awk
User LOGIN LOGIN_IP TIME
---------------------------------------------
root pts/0 192.168.10.102 6.00s
10. 根據需求截取數據長度
[root@localhost Awk0-script]# gawk -f fw.awk fw.in
3 12 34a bcde
### fw.awk #####
BEGIN { FIELDWIDTHS = "2 3 4" }
{ print NF, $1, $2, $3 }
#############
@@@@ fw.in @@@@@@@
1234abcdefghi
注 awk 4.2版本以後支持最後一參數爲 " * " ,匹配餘下的字符串,
詳見: 4.6.3 Capturing Optional Trailing Data
11. 使用awk(gawk)解析csv文件
[root@localhost Awk0-script]# vim address.csv
Robbins,Arnold,"1234 A Pretty Street, NE",MyTown,MyState,12345-6789,USA
[root@localhost Awk0-script]# vim process-csv.awk
########
BEGIN {
FPAT = "([^,]+)|(\"[^\"]+\")" # 匹配字段的正則表達式
}
{
print "NF = ", NF #輸出總的記錄數
for (i = 1; i <= NF; i++) { # 輸出記錄
printf("$%d = <%s>\n", i, $i)
}
}
#######
[root@localhost Awk0-script]# gawk -f process-csv.awk address.csv
NF= 7
$1= <Robbins>
$2= <Arnold>
$3= <"1234 A Pretty Street, NE"> ## 沒有正常顯示數據,需要去掉引號
$4= <MyTown>
$5= <MyState>
$6= <12345-6789>
$7= <USA>
改進之後的結果是:
###改進的方法是使用awk的 substr(str,index,len) 處理
if (substr($i, 1, 1) == "\"") {
len = length($i)
$i = substr($i, 2, len - 2) # 獲取不包含雙引號的子串
}
[root@localhost Awk0-script]# gawk -f process-csv.awk address.csv
NF= 7
$1= <Robbins>
$2= <Arnold>
$3= <1234 A Pretty Street, NE>
$4= <MyTown>
$5= <MyState>
$6= <12345-6789>
$7= <USA>
12. 使用awk(gawk)處理多行數據
[root@localhost Awk0-script]# gawk -f addr.awk address
######## addr.awk #####
# Each line is one field.
BEGIN {RS = ""; FS = "\n"} # RS:記錄分隔符 FS:字段分隔符(其爲空或者regx RS無效)
{
printf "Name is:%s,Address is:%s,City and State are :%s \n",$1,$2,$3
}
######################
Name is:Jane Doe,Address is:123 Main Street,City and State are :Anywhere, SE 12345-6789
Name is:John Smith,Address is:456 Tree-lined Avenue,City and State are :Smallville, MW 98765-4321
[root@localhost Awk0-script]# cat address
Jane Doe
123 Main Street
Anywhere, SE 12345-6789
John Smith
456 Tree-lined Avenue
Smallville, MW 98765-4321
附錄:awk內建變量
變量(Variable) | 說明(Description) | 示例(Example) |
---|---|---|
$n | 當前記錄的第n個字段,默認由FS分隔(tab或空格) | awk ‘{print $1}’ file |
$0 | 完整的輸入記錄 | awk ‘{print $0}’ file |
ARGC | 命令行參數的數目 | |
ARGIND | 命令行參數當前文件的index | awk ‘/^A/ {print ARGIND}’ mail-list.txt |
ARGV | 包含命令行參數的數組 | |
CONVFMT | 數字轉換格式(默認值爲%.6g)ENVIRON環境變量關聯數組 | |
ERRNO | 最後一個系統錯誤的描述 | |
FIELDWIDTHS | 字段寬度列表(用空格分隔) | |
FILENAME | 當前文件名 | awk ‘/^A/ {print FILENAME}’ file |
FNR | 各文件分別計數的行號 | awk ‘/^A/ {print FNR}’ |
FS | 字段分隔符(默認是任何空格) | |
IGNORECASE | 如果爲1,則進行忽略大小寫的匹配 | |
NF | 一條記錄的字段的數目(即列) | |
NR | 記錄數的行號 | |
OFMT | 數字的輸出格式(默認值是%.6g) | |
OFS | 輸出記錄分隔符(輸出換行符),輸出時用指定的符號代替換行符 | |
ORS | 輸出記錄分隔符(默認值是一個換行符) | |
RLENGTH | 由match函數所匹配的字符串的長度 | |
RS | 記錄分隔符(默認是一個換行符) | |
RSTART | 由match函數所匹配的字符串的第一個位置 | |
SUBSEP | 數組下標分隔符(默認值是/034) |