awk 内嵌正则 提取字符串_干货-Shell编程文本处理三剑客之-awk
awk
在 Linux/UNIX 系統中,awk 是一個功能強大的編輯工具,逐行讀取輸入文本,并根據指定的匹配模式進行查找,對符合條件的內容進行格式化輸出或者過濾處理,可以在無交互的情況下實現相當復雜的文本操作,被廣泛應用于 Shell 腳本,完成各種自動化配置任務。
AWK是一種處理文本文件的語言,是一個強大的文本分析工具。之所以叫 AWK 是因為其取了三位創始人 Alfred Aho,Peter Weinberger, 和 Brian Kernighan 的 Family Name 的首字符。
語法格式:
語法格式解釋:
| BEGIN{} | 正式處理數據之前執行 |
| pattern | 匹配模式 |
| {commands} | 處理命令,可能多行 |
| END{} | 處理完所有匹配數據后執行 |
awk內置變量
| $0 | 整行內容 |
| $1~$n | 當前行的第1-n個字段 |
| NF | 當前行的字段個數,也就是有多少列 |
| NR | 當前行的行號,從1開始計數 |
| FNR | 多文件處理時,每個文件行號單獨計數都是從0開始 |
| FS | 輸入字段分隔符,不指定則默認以空格或tab鍵分隔 |
| RS | 輸入行分隔符,默認回車換行 |
| OFS | 輸出字段分隔符,默認為空格 |
| ORS | 輸出行分隔符,默認回車換行 |
| FILENAME | 當前輸入的文件名字 |
| ARGC | 命令行參數個數 |
| ARGV | 命令行參數數組 |
示例
以下所有示例文件為/etc/passwd,請將其拷貝一份使用
# 打印整行內容 awk '{print $0}' passwd# 使用":"號作為分隔符,輸出第一個字段 awk 'BEGIN{FS=":"}{print $1}' passwd ->root ->bin ->daemon ->adm ->lp ->sync ->shutdown ->...# 輸出行號 awk '{print NR}' passwd# 多個文件行號單獨計數 awk '{print FNR}' passwd file2# 指定行分隔符 echo "hello-world-hello-linux-hello-java" | awk 'BEGIN{RS="-"}{print $0}' ->hello ->world ->hello ->linux ->hello ->java -># 指定輸出字段分隔符 awk 'BEGIN{FS=":";OFS=":"}{print NR,$1}' passwd ->1:root ->2:bin ->3:daemon ->4:adm ->5:lp ->...printf格式化輸出
| %s | 打印字符串 |
| %d | 打印十進制數 |
| %f | 打印一個浮點數 |
| %x | 打印十六進制數 |
| %o | 打印八進制數 |
| %e | 打印數字的科學計數法形式 |
| %c | 打印單個字符的ASCII碼 |
| - | 左對齊 |
| + | 右對齊 |
| # | 顯示8進制在前面加0,顯示16進制在前面加0x |
示例
# 以字符串格式打印第1個字段,以":"作為分隔符 awk 'BEGIN{FS=":"}{printf "%st",$1}' passwd ->root bin daemon adm lp ...# 以字符串格式打印第1個字段和對應行號,輸出格式為"行號:字段內容" awk 'BEGIN{FS=":"}{printf "%d:%sn",NR,$1}' passwd ->1:root ->2:bin ->3:daemon ->4:adm ->5:lp ->...# 左對齊 # 在不指定位數的情況下默認左對齊,指定位數后為右對齊(必須指定位數) awk 'BEGIN{FS=":"}{printf "%10d:%sn",NR,$1}' passwd -> 1:root -> 2:bin -> 3:daemon -> 4:adm -> 5:lp ->...awk 'BEGIN{FS=":"}{printf "%-10d:%sn",NR,$1}' passwd ->1 :root ->2 :bin ->3 :daemon ->4 :adm ->5 :lp ->...兩種匹配模式
| 正則 | 按正則表達式匹配 |
| 關系運算 | 按關系運算匹配 |
關系運算符:
- < : 小于
- > : 大于
- <= : 小于等于
- >= : 大于等于
- == : 等于
- != : 不等于
- ~ : 匹配正則表達式
- !~ : 不匹配正則表達式
布爾運算符:
- || : 或
- && : 與
- ! : 非
awk表達式
# 統計空白行數目 awk '/^$/{sum++}END{print sum}' /etc/services ->17# 統計一下學生成績總分和平均分,報表形式展示 姓名 語文 數學 英語 物理 張三 80 60 85 90 李四 85 65 80 75 王五 70 60 85 90 李華 65 80 84 91 王八 90 90 95 90awk 'BEGIN{printf "%-8s%-5s%-5s%-5s%-5s%-5s%-8sn","姓名","語文","數學","英語","物理","總分","平均分"}{total=$2+$3+$4+$5;avg=total/4;printf "%-8s%-8d%-6d%-8d%-7d%-5d%0.2fn",$1,$2,$3,$4,$5,total,avg}' stu.txt姓名 語文 數學 英語 物理 總分 平均分 張三 80 60 85 90 315 78.75 李四 85 65 80 75 305 76.25 王五 70 60 85 90 305 76.25 李華 65 80 84 91 320 80.00 王八 90 90 95 90 365 91.25條件語句和循環語句
# 條件語句 if (條件表達式1){action1 }else if (條件表達式2){action2 }else{action3 }# 以":"為分隔符,如果第3個字段小于50,打印小于50,如果等于50則打印等于50,否則打印大于50 awk 'BEGIN{FS=":"}{if($3<50){print "小于50" }else if($3==50){ print "等于50"}else{print "大于50"}}' passwd# 我們可以將命令保存在一個文件(eg:oper.awk,后綴不硬性要求哦!)中使用-f選項引入 awk -f oper.awk passwd# 循環語句 while while(條件表達式){action }# 循環語句 do while do{action }while(條件表達式)# 循環語句 for for(初始化計數器;測試計數器;變更計數器){action }# 計算1+2+3+...+100的和。 awk 'BEGIN{do{i++;sum+=i;}while(i<100)print sum}' awk 'BEGIN{while(i<100){i++;sum+=i;}print sum}' awk 'BEGIN{for(i=0;i<=100;i++){sum+=i;}print sum}'字符串函數
| 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,替換所有 | 替換的個數 |
示例
# 以:為分隔符,返回文件每行中每個字段的長度 awk 'BEGIN{FS=":"}{for(i=1;i<=NF;i++){if(i==NF){printf "%d",length($i)}else{printf "%d:",length($i)}}print ""}' passwd# 搜索字符串"I am a student"中student子串的位置 echo "I am a student" | awk '{print index($0,"student")}' ->8awk常用選項
| -v | 參數傳遞 |
| -f | 指定腳本文件 |
| -F | 指定分隔符 |
| -V | 查看awk版本號 |
數組
awk中數組使用小括號包圍起來,每一項之間使用空格分隔,如:arr=("one" "two" "three" "four" "five").在awk中數組下標從1開始,需要注意哦~。 awk可以使用關聯數組這種數據結構,索引可以是數字或字符串。awk關聯數 組也不需要提前聲明其大小,因為它在運行時可以自動的增大或減小。
# 統計主機上所有的TCP,按照TCP狀態進行分類 netstat -an | grep tcp | awk '{array[$6]++}END{for(item in array){print item,array[item]}}' ->LISTEN 8 ->ESTABLISHED 26awk文件處理
awk 可以直接處理目標文件,也可以通過“-f”讀取腳本對目標文件進行處理。
(1) awk 比較傾向于將一行分成多個“字段”然后再進行處理,且默認情況下字段的分隔符為空格或者 tab 鍵。awk 執行結果可以通過 print 的功能將字段數據打印顯示。在使用 awk 命令的過程中,可以使用
邏輯操作符如下所示:
*“&&”,表示“與”* *“||”,表示“或”* *“!”,表示“非”*簡單的數學運算如下:
+、-、*、/、%、^分別 表示加、減、乘、除、取余和乘方(2)在 Linux 系統中/etc/passwd 是一個非常典型的格式化文件,各字段間使用“:”作為分隔符隔開,Linux 系統中的大部分日志文件也是格式化文件,從這些文件中提取相關信息是運維的日常工作內容之一。
例如:需要查找出/etc/passwd 的用戶名、用戶 ID、組 ID 等列, 執行以下 awk 命令即可。
[root@localhost ~]# awk -F ':' '{print $1,$3,$4}' /etc/passwd root 0 0 bin 1 1 daemon 2 2 adm 3 4 lp 4 7 sync 5 0 shutdown 6 0 halt 7 0 mail 8 12 operator 11 0 games 12 100 ftp 14 50 //省略部分內容awk 從輸入文件或者標準輸入中讀入信息,與 sed 一樣,信息的讀入也是逐行讀取的。不同的是 awk 將文本文件中的一行視為一個記錄,而將一行中的某一部分(列)作為記錄中的一個字段(域)。為了操作這些不同的字段,awk 借用 shell 中類似于位置變量的方法, 用$1、$2、$3?順序地表示行(記錄)中的不同字段。另外 awk 用$0 表示整個行(記錄)。不同的字段之間是通過指定的字符分隔。awk 默認的分隔符是空格。awk 允許在命令行中用“-F 分隔符”的形式來指定分隔符。因此,上述示例中,awk 命令對/etc/passwd 文件的處理過程如圖 所示:
awk工作原理圖(3)awk 包含幾個特殊的內建變量(可直接用):
- FS:指定每行文本的字段分隔符,默認為空格或制表位。
- NF:當前處理的行的字段個數。
- NR:當前處理的行的行號(序數)。
- $0:當前處理的行的整行內容。
- $n:當前處理行的第 n 個字段(第 n 列)。
- FILENAME:被處理的文件名。
- RS:數據記錄分隔,默認為n,即每行為一條記錄。
用法示例
(1)按行輸出文本
輸出所有內容
[root@localhost opt]# awk '{print}' test.txt //輸出所有內容,等同于 cat test.txt或者
[root@localhost opt]# awk '{print $0}' test.txt //輸出所有內容,等同于 cat test.txt輸出1-3行內容
[root@localhost opt]# awk 'NR==1,NR==3{print}' test.txt //輸出第 1~3 行內容 root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin或者
[root@localhost opt]# awk '(NR>=1)&&(NR<=3){print}' test.txt //輸出第 1~3 行內容 root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin輸出以root 開頭的行
[root@localhost opt]# awk '/^root/{print}' /etc/passwd root:x:0:0:root:/root:/bin/bash輸出以 nologin 結尾的行
[root@localhost opt]# awk '/nologin$/{print}' /etc/passwd bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin mail:x:8:12:mail:/var/spool/mail:/sbin/nologin operator:x:11:0:operator:/root:/sbin/nologin games:x:12:100:games:/usr/games:/sbin/nologin ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin nobody:x:99:99:Nobody:/:/sbin/nologin systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin dbus:x:81:81:System message bus:/:/sbin/nologin polkitd:x:999:998:User for polkitd:/:/sbin/nologin abrt:x:173:173::/etc/abrt:/sbin/nologin libstoragemgmt:x:998:996:daemon account for libstoragemgmt:/var/run/lsm:/sbin/nologin rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin colord:x:997:995:User for colord:/var/lib/colord:/sbin/nologin saslauth:x:996:76:Saslauthd user:/run/saslauthd:/sbin/nologin rtkit:x:172:172:RealtimeKit:/proc:/sbin/nologin pulse:x:171:171:PulseAudio System Daemon:/var/run/pulse:/sbin/nologin chrony:x:995:991::/var/lib/chrony:/sbin/nologin rpcuser:x:29:29:RPC Service User:/var/lib/nfs:/sbin/nologin nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin ntp:x:38:38::/etc/ntp:/sbin/nologin tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin usbmuxd:x:113:113:usbmuxd user:/:/sbin/nologin geoclue:x:994:989:User for geoclue:/var/lib/geoclue:/sbin/nologin qemu:x:107:107:qemu user:/:/sbin/nologin radvd:x:75:75:radvd user:/:/sbin/nologin setroubleshoot:x:993:988::/var/lib/setroubleshoot:/sbin/nologin sssd:x:992:987:User for sssd:/:/sbin/nologin gdm:x:42:42::/var/lib/gdm:/sbin/nologin gnome-initial-setup:x:991:986::/run/gnome-initial-setup/:/sbin/nologin sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin avahi:x:70:70:Avahi mDNS/DNS-SD Stack:/var/run/avahi-daemon:/sbin/nologin postfix:x:89:89::/var/spool/postfix:/sbin/nologin tcpdump:x:72:72::/:/sbin/nologin apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin dhcpd:x:177:177:DHCP server:/:/sbin/nologin統計以/bin/bash 結尾的行數,等同于 grep -c "/bin/bash$" /etc/passwd
[root@localhost opt]# awk 'BEGIN{X=0};//bin/bash$/{x++};END{print x}' /etc/passwd 11統計以空行分隔的文本段落數
[root@localhost ~]# awk 'NEGIN{RS=""};END{print NR}' /etc/passwd 52(2)按字段輸出文本
輸出每行中(以空格或制表位分隔)的第 3 個字段
[root@localhost ~]# awk '{print $3}' /etc/passwdManagement:/:/sbin/nologinbus:/:/sbin/nologinpolkitd:/:/sbin/nologinforcolord:/var/lib/colord:/sbin/nologinDaemon:/var/run/pulse:/sbin/nologinUser:/var/lib/nfs:/sbin/nologin User:/var/lib/nfs:/sbin/nologinbygeoclue:/var/lib/geoclue:/sbin/nologinsssd:/:/sbin/nologinStack:/var/run/avahi-daemon:/sbin/nologin[root@localhost ~]#輸出每行中的第 1、3 個字段
[root@localhost ~]# awk '{print $1,$3}' /etc/passwd root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin sync:x:5:0:sync:/sbin:/bin/sync輸出密碼為空的用戶的shadow 記錄
[root@localhost ~]# awk -F ":" '$2==""{print}' /etc/shadow或者
[root@localhost ~]# awk 'BEGIN{FS=":"};$2==""{print}' /etc/shadow輸出以冒號分隔且第 7 個字段中包含/bash 的行的第 1 個字段
[root@localhost ~]# awk -F ":" '$7~"/bash"{print $1}' /etc/passwd root shan lisi wangwu zhangsan liuliu c xiao jing tol jiji sfya輸出包含 8 個字段且第 1 個字段中包含 nfs 的行的第 1、2 個字段
[root@localhost ~]# awk '($1~"nfs")&&(NF==8){print $1,$2}' /etc/services nfs 2049/tcp nfs 2049/udp nfs 2049/sctp netconfsoaphttp 832/tcp netconfsoaphttp 832/udp netconfsoapbeep 833/tcp netconfsoapbeep 833/udp輸出第 7 個字段既不為/bin/bash 也不為/sbin/nologin 的所有行
[root@localhost ~]# awk -F ":" '($7!="/bin/bash")&&($7!="/sbin/nologin"){print}' /etc/passwd sync:x:5:0:sync:/sbin:/bin/sync shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown halt:x:7:0:halt:/sbin:/sbin/halt*(3)通過管道、雙引號調用 Shell 命令*
調用wc -l 命令統計使用bash 的用戶個數,等同于 grep -c "bash$" /etc/passwd
[root@localhost ~]# awk -F : '/bash$/{print | "wc -l"}' /etc/passwd 12調用w 命令,并用來統計在線用戶數
[root@localhost ~]# awk 'BEGIN{while("w" | getline)n++;{print n-2}}' 4調用hostname,并輸出當前的主機名
[root@localhost ~]# awk 'BEGIN{"hostname" | getline;print $0}' localhost.localdomain總結
以上是生活随笔為你收集整理的awk 内嵌正则 提取字符串_干货-Shell编程文本处理三剑客之-awk的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python如何让用户输入文件名并打开文
- 下一篇: python快速排序最简单写法_漫画:最