Linux文字三劍客總結

上善若水~小輝發表於2021-03-01

Linux文字處理三劍客

grep

文字過濾(模式:pattern)工具 grep, egrep, fgrep(不支援正規表示式搜尋)

grep

 grep: Global search REgular expression and Print out the line
 作用:文字搜尋工具,根據使用者指定的“模式”對目標文字逐行進行匹配檢查;列印匹配到的行
 模式:由正規表示式字元及文字字元所編寫的過濾條件
 grep [OPTIONS] PATTERN [FILE...]
 grep root /etc/passwd
 grep "$USER" /etc/passwd
 grep '$USER' /etc/passwd
 grep `whoami` /etc/passwd

grep命令選項

 --color=auto: 對匹配到的文字著色顯示
 -m # 匹配#次後停止
 -v 顯示不被pattern匹配到的行
 -i 忽略字元大小寫
 -n 顯示匹配的行號
 -c 統計匹配的行數
 -o 僅顯示匹配到的字串
 -q 靜默模式,不輸出任何資訊
 -A # after, 後#行
 -B # before, 前#行
 -C # context, 前後各#行
 -e 實現多個選項間的邏輯or關係
 grep –e ‘cat -e ‘dog’ file
 -w 匹配整個單詞
 -E 使用ERE
 -F 相當於fgrep,不支援正規表示式
 -f file 根據模式檔案處理

正規表示式

 REGEXP: Regular Expressions,由一類特殊字元及文字字元所編寫的模式,其中有些字元(元字元)不表示字元字面意義,而表示控制或通配的功能
 程式支援:grep,sed,awk,vim, less,nginx,varnish等
 分兩類:
 基本正規表示式:BRE
 擴充套件正規表示式:ERE
 grep -E, egrep
 正規表示式引擎:
 採用不同演算法,檢查處理正規表示式的軟體模組
 PCRE(Perl Compatible Regular Expressions)
 元字元分類:字元匹配、匹配次數、位置錨定、分組
 man 7 regex

基本正規表示式元字元 字元匹配:

 . 匹配任意單個字元
 [] 匹配指定範圍內的任意單個字元,示例:[wang] [0-9] [a-z] [a-zA-Z]
 [^] 匹配指定範圍外的任意單個字元
 [:alnum:] 字母和數字
 [:alpha:] 代表任何英文大小寫字元,亦即 A-Z, a-z
 [:lower:] 小寫字母 [:upper:] 大寫字母
 [:blank:] 空白字元(空格和製表符)
 [:space:] 水平和垂直的空白字元(比[:blank:]包含的範圍廣)
 [:cntrl:] 不可列印的控制字元(退格、刪除、警鈴...
 [:digit:] 十進位制數字 [:xdigit:]十六進位制數字
 [:graph:] 可列印的非空白字元
 [:print:] 可列印字元
 [:punct:] 標點符號
 匹配次數:用在要指定次數的字元後面,用於指定前面的字元要出現的次數
 匹配前面的字元任意次,包括0次
 貪婪模式:儘可能長的匹配
 .* 任意長度的任意字元
 \? 匹配其前面的字元0或1次
 \+ 匹配其前面的字元至少1次
 \{n\} 匹配前面的字元n次
 \{m,n\} 匹配前面的字元至少m次,至多n次
 \{,n\} 匹配前面的字元至多n次
 \{n,\} 匹配前面的字元至少n次

位置錨定:定位出現的位置

 ^ 行首錨定,用於模式的最左側
 $ 行尾錨定,用於模式的最右側
 ^PATTERN$ 用於模式匹配整行
 ^$ 空行
 ^[[:space:]]*$ 空白行
 \< \b 詞首錨定,用於單詞模式的左側
 \> \b 詞尾錨定,用於單詞模式的右側
 \<PATTERN\> 匹配整個單詞
 分組:\(\) 將一個或多個字元捆綁在一起,當作一個整體處理,如:\(root\)\+
 分組括號中的模式匹配到的內容會被正規表示式引擎記錄於內部的變數中,這些變數的命名方式為: \1, \2, \3, ...
 \1 表示從左側起第一個左括號以及與之匹配右括號之間的模式所匹配到的字元
 示例: \(string1\(string2\)\)
 \1 :string1\(string2\)
 \2 :string2
 後向引用:引用前面的分組括號中的模式所匹配字元,而非模式本身
 或者:\|
 示例:a\|b a或b
 C\|cat C或cat
 \(C\|c\)at Cat或cat

 

 

 

 

 

 

 

練習題:

1、顯示/proc/meminfo檔案中以大小s開頭的行(要求:使用兩種方法)

 [root@shell ~]# grep -in '^s' /proc/meminfo 
 [root@shell ~]# cat /proc/meminfo |grep "^[sS]"
 cat /proc/meminfo | grep '^[sS]'  # 匹配開頭[sS]任意單個字元
 cat /proc/meminfo | grep '^[s\|S]'  # 匹配開頭s或者S
 grep '^s\|^S' /proc/meminfo   # 匹配開頭s或者開頭S
 grep -i '^s' /proc/meminfo  # 匹配開頭s忽略大小寫

2、顯示/etc/passwd檔案中不以/bin/bash結尾的行

 [root@shell ~]#cat /etc/passwd |grep -nv “/bin/bash$”

3、顯示使用者rpc預設的shell程式

 cat /etc/passwd | grep -w '^root' | grep -o '[^/]\+$'

4、找出/etc/passwd中的兩位或三位數

 grep "\b[0-9]\{2,3\}\b" /etc/passwd  # \b 詞首錨定,\b 詞尾錨定
 grep '\<[0-9]\{2,3\}\>' /etc/passwd  # \< 詞首錨定,\> 詞尾錨定
 grep -w '[0-9]\{2,3\}' /etc/passwd
 egrep -w '[0-9]{2,3}' /etc/passwd

5、顯示CentOS7的/etc/grub2.cfg檔案中,至少以一個空白字元開頭的且後面有非空白字元的行

 grep '^[[:space:]]\+[^[:graph:]]' /etc/grub2.cfg
 egrep '^[[:space:]]+[^[:graph:]]' /etc/grub2.cfg

6、找出“netstat -tan”命令結果中以LISTEN後跟任意多個空白字元結尾的行

 netstat -tan | grep 'LISTEN[[:space:]]*$'

7、顯示CentOS7上所有UID小於1000以內的使用者名稱和UID

 cut -d: -f 1,3 /etc/passwd | grep '\<[0-9]\{0,3\}\>'  # 匹配任意數字至少0個字元,至多3個字元
 cut -d: -f 1,3 /etc/passwd | grep '\b[0-9]\{0,3\}\b'
 cut -d: -f 1,3 /etc/passwd | grep -w '[0-9]\{0,3\}'
 cut -d: -f 1,3 /etc/passwd | egrep -w '[0-9]{0,3}'
 cut -d: -f 1,3 /etc/passwd | tr : ' ' | awk '{if($2<1000)print $1,$2}'| tr ' ' :

8、新增使用者bash、testbash、basher、sh、nologin(其shell為/sbin/nologin),找出/etc/passwd使用者名稱和shell同名的行

useradd bash && useradd testbash && useradd basher && useradd sh && useradd -s /sbin/nologin nologin
 cat /etc/passwd | grep '\(^[a-zA-Z0-9]\+\>\).*\<\1$'
 cat /etc/passwd | egrep '(^[[:alnum:]]+\>).*\<\1$'  

 # 匹配以任意數字或字母開頭的單詞至少一次,放入內建變數 \1,再匹配任意字元任意次直到結尾前一個單詞是 \1

9、利用df和grep,取出磁碟各分割槽利用率,並從大到小排序

 df | grep ^/dev | grep -o '[0-9]\{1,\}%'|sort -nr  # -o 只顯示匹配的字串
 df | grep ^/dev | egrep -o '[0-9]{1,}%'|sort -nr  # {1,} 匹配前一個字元至少1次

egrep

egrep及擴充套件的正規表示式

egrep = grep -E egrep [OPTIONS] PATTERN [FILE...] 擴充套件正規表示式的元字元: 字元匹配: . 任意單個字元 [] 指定範圍的字元 [^] 不在指定範圍的字元

擴充套件正規表示式

 次數匹配:
 .匹配前面字元任意次
 ? 0或1次
 + 1次或多次
 {m} 匹配m次
 {m,n} 至少m,至多n次

擴充套件正規表示式 位置錨定:

 ^ 行首
 $ 行尾
 \<, \b 語首
 \>, \b 語尾
 分組:
 ()
 後向引用:\1, \2, ...
 或者:
 a|b a或b
 C|cat C或cat
 (C|c)at Cat或cat

練習題:

1、顯示三個使用者root、mage、wang的UID和預設shell

 cut -d: -f1,3,7 /etc/passwd | grep -w '^\(root\|mage\|wang\)'
 cut -d: -f1,3,7 /etc/passwd | egrep -w '^(root|mage|wang)'

2、找出/etc/rc.d/init.d/functions檔案中行首為某單詞(包括下劃線)後面跟一個小括號的行

 egrep -o '^.*\(\)' /etc/rc.d/init.d/functions
 grep -o '^[a-zA-Z0-9_].*()' /etc/rc.d/init.d/functions
 grep -o '^[[:alnum:]_].*()' /etc/rc.d/init.d/functions

3、使用egrep取出/etc/rc.d/init.d/functions中其基名

 echo /etc/rc.d/init.d/functions | egrep -o '[^/]+$'
 # 從最後一個字元開始向前匹配,排除/至少一次後停止
 echo /etc/rc.d/init.d/functions | egrep -ow '[[:alnum:]]+$'

 # 從最後一個字元開始向前匹配,匹配到任意字母或數字組成的單詞至少一次後停止,基名不能有特殊字元

4、使用egrep取出上面路徑的目錄名

 echo /etc/rc.d/init.d/functions | egrep -o  '.*/\<'
 root@shell ~]# echo /etc/rc.d/init.d/functions | egrep -o  '.*/\b'
 /etc/rc.d/init.d/
 [root@shell ~]# echo /etc/rc.d/init.d/functions | grep -o  '.*/\+\b'
 /etc/rc.d/init.d/

5、統計last命令中以root登入的每個主機IP地址登入次數

 last | grep '^root' | awk '{print $1,$3}'| grep -v '[a-z]$'| sort | uniq -c
 # 篩選root登陸;篩選只顯示使用者和主機IP;排除沒有主機IP的行(不顯示以任意字母結尾的行);排序;統計
last | grep ^root | egrep -o "([0-9]{1,3}\.){3}[0-9]{1,3}" | sort | uniq -c
 # 篩選root登陸;篩選只顯示主機IP;排序;統計

6、利用擴充套件正規表示式分別表示0-9、10-99、100-199、200-249、250-255

 echo {1..255} | egrep -wo '[0-9]' | tr "\n" " " ; echo
 echo {1..255} | egrep -wo '[1-9][0-9]' | tr "\n" " " ; echo
 echo {1..255} | egrep -wo '1[0-9]{2}' | tr "\n" " " ; echo
 echo {1..255} | egrep -wo '2[0-4][0-9]' | tr "\n" " " ; echo
 echo {1..255} | egrep -wo '25[0-5]' | tr "\n" " " ; echo

7、顯示ifconfig命令結果中所有IPv4地址

 ifconfig | egrep -o "\<(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4]0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\>"

8、將此字串:welcome to magedu linux 中的每個字元去重並排序,重複次數多的排到前面

 echo "welcome to magedu linux" | tr -d " " | egrep -o "." | sort | uniq -c | sort -nr

 # 刪除空格;拆分字元到每行(只顯示匹配到的任意字元的行);排序;去重;按第一行數字降序排序

sed

stream editor,文字編輯工具

Stream EDitor, 行編輯器 sed是一種流編輯器,它一次處理一行內容。處理時,把當前處理的行儲存在臨時緩衝區中,稱為“模式空間”(pattern space),接著用sed命令處理緩衝區中的內容,處理完成後,把緩衝區的內容送往螢幕。然後讀入下行,執行下一個迴圈。如果沒有使諸如‘D’的特殊命令,那會在兩個迴圈之間清空模式空間,但不會清空保留空間。這樣不斷重複,直到檔案末尾。檔案內容並沒有改變,除非你使用重定向儲存輸出。 功能:主要用來自動編輯一個或多個檔案,簡化對檔案的反覆操作,編寫轉換程式等 參考: http://www.gnu.org/software/sed/manual/sed.html

sed工具

用法:

 sed [option]... 'script' inputfile...
 常用選項:
 -n 不輸出模式空間內容到螢幕,即不自動列印
 -e 多點編輯
 -f /PATH/SCRIPT_FILE 從指定檔案中讀取編輯指令碼
 -r 支援使用擴充套件正規表示式
 -i.bak 備份檔案並原處編輯
 script:
 '地址命令'

地址定界:

 (1) 不給地址:對全文進行處理
 (2) 單地址:
 #:指定的行,$:最後一行
 /pattern/:被此處模式所能夠匹配到的每一行
 (3) 地址範圍:
 #,#
 #,+#
 /pat1/,/pat2/
 #,/pat1/
 (4) ~:步進
 1~2 奇數行
 2~2 偶數行

編輯命令:

 d 刪除模式空間匹配的行,並立即啟用下一輪迴圈
 p 列印當前模式空間內容,追加到預設輸出之後
 a [\]text 在指定行後面追加文字,支援使用\n實現多行追加
 i [\]text 在行前面插入文字
 c [\]text 替換行為單行或多行文字
 w /path/file 儲存模式匹配的行至指定檔案
 r /path/file 讀取指定檔案的文字至模式空間中匹配到的行後
 = 為模式空間中的行列印行號
 ! 模式空間中匹配行取反處理

 s/// 查詢替換,支援使用其它分隔符,s@@@,s###
 替換標記:
 g 行內全域性替換
 p 顯示替換成功的行
 w /PATH/FILE 將替換成功的行儲存至檔案中

sed示例

 
sed ‘2p’ /etc/passwd
 sed -n ‘2p’ /etc/passwd
 sed -n ‘1,4p’ /etc/passwd
 sed -n ‘/root/p’ /etc/passwd
 sed -n ‘2,/root/p’ /etc/passwd 從2行開始
 sed -n ‘/^$/=’ file 顯示空行行號
 sed -n -e ‘/^$/p’ -e ‘/^$/=’ file
 Sed‘/root/a\superman’ /etc/passwd行後
 sed ‘/root/i\superman’ /etc/passwd 行前
 sed ‘/root/c\superman’ /etc/passwd 代替行
 sed ‘/^$/d’ file
 sed ‘1,10d’ file
 nl /etc/passwd | sed ‘2,5d’
 nl /etc/passwd | sed ‘2a tea’
 sed 's/test/mytest/g' example
 sed –n ‘s/root/&superman/p’ /etc/passwd 單詞後
 sed –n ‘s/root/superman&/p’ /etc/passwd 單詞前
 sed -e ‘s/dog/cat/’ -e ‘s/hi/lo/’ pets
 sed –i.bak ‘s/dog/cat/g’ pets
 sed [options] 'script' inputfile...
 sed [options] -f scriptfile file(s)
     -e<script>,--expression=<script>    以指定的 script 來處理輸入的檔案,用於順序執行多條命令
     -f<script 檔案>,--file=<script 檔案> 以指定的 script 檔案來處理輸入的檔案
     -n,--quiet,——silent                  取消自動列印模式空間
     -i[SUFFIX], --in-place[=SUFFIX]      直接編輯檔案(如果提供字尾,則進行備份)
     -r                                   使用擴充套件正規表示式
 sed元字符集
 ^         匹配行開始,如:/^sed/匹配所有以sed開頭的行。
 $         匹配行結束,如:/sed$/匹配所有以sed結尾的行。
 .         匹配一個非換行符的任意字元,如:/s.d/匹配s後接一個任意字元,最後是d。
 *         匹配0個或多個字元,如:/*sed/匹配所有模板是一個或多個空格後緊跟sed的行。
 []        匹配一個指定範圍內的字元,如/[ss]ed/匹配sed和Sed。  
 [^]       匹配一個不在指定範圍內的字元,如:/[^A-RT-Z]ed/匹配不包含A-R和T-Z的一個字母開頭,緊跟ed的行。
 \(..\)    匹配子串,儲存匹配的字元,如s/\(love\)able/\1rs,loveable被替換成lovers。
 &         儲存搜尋字元用來替換其他字元,如s/love/**&**/,love這成**love**。
 \<        匹配單詞的開始,如:/\<love/匹配包含以love開頭的單詞的行。
 \>        匹配單詞的結束,如/love\>/匹配包含以love結尾的單詞的行。
 x\{m\}    重複字元x,m次,如:/0\{5\}/匹配包含5個0的行。
 x\{m,\}   重複字元x,至少m次,如:/0\{5,\}/匹配至少有5個0的行。
 x\{m,n\}  重複字元x,至少m次,不多於n次,如:/0\{5,10\}/匹配5~10個0的行。
 ​
 sed地址定界:預設對全文進行處理
 #              指定行
 $              最後一行
 /pattern/      被 pattern 匹配到的每一行
 #,#            區間
 #,+#           區間 +#=#+1
 /pat1/,/pat2/
 #,/pat1/
 first~step     步進(stepping) 先定位 first 所在行,然後每經過step行再定位一次
 1~2            奇數行
 2~2            偶數行
 first,~N       從 first 所在的行至往後第一個可以被N整除的行
 ​
 GNU擴充套件的sed,支援特殊序列(special sequence),它由一個反斜線和一個字母組成:
 \L:將replacement替換成小寫直到遇到\U或者\E。
 \l:將下一個字元替換成小寫。
 \U:將replacement替換成大寫直到遇到\L或者\E。
 \u:將下一個字元替換成大寫。
 \E:停止\U或者\L帶來的大小寫轉換功能。
 Examples:
 sed '2p' /etc/passwd                    列印檔案內容,並重復列印檔案第2行
 sed -n '2p' /etc/passwd                 只列印檔案第2行
 sed -n '1,4p' /etc/passwd               只列印檔案第1到4行
 sed -n '/root/p' /etc/passwd            只列印檔案匹配 root 的行
 sed -n '2,/root/p' /etc/passwd          只列印檔案從第2行開始到匹配 root 的行
 sed -n '/^$/=' file                     顯示空行行號(只列印檔案匹配 ^$ 的行及其行號)
 sed -n -e '/^$/p' -e '/^$/=' file       只列印檔案空行和空行及其行號
 sed '/root/a superman' /etc/passwd      匹配 root 的行後追加一行 superman
 sed '/root/i superman' /etc/passwd      匹配 root 的行前追加一行 superman
 sed '/root/c superman' /etc/passwd      用 superman 代替匹配 root 的行
 nl /etc/passwd | sed '2a tea'           檔案第2行後追加一行 tea
 sed -n 's/root/&superman/p' /etc/passwd 只列印匹配 root 單詞後追加 superman 單詞的行
 sed -n 's/root/superman&/p' /etc/passwd 只列印匹配 root 單詞前追加 superman 單詞的行
 sed -i.bak 's/dog/cat/g' file           備份.bak 後,在原檔案中替換並儲存
 sed -i.bak 's/dog/cat/g' file           備份.bak 後,在原檔案中替換並儲存
 ​
 已匹配字串標記&
 sed 's/\w\+/[&]/g' file      #  \w\+ 匹配每一個單詞
 替換操作:s命令
 sed 's/book/books/' file
 sed -n 's/test/TEST/p' file  # -n 抑制自動列印原文字,p 列印處理後的行。只列印發生替換的行
 刪除操作:d命令
 sed '/^$/d' file     刪除空白行
 sed '/^test/d' file  刪除檔案中所有開頭是test的行
 sed '2d' file        刪除檔案的第2行
 sed '$d' file        刪除檔案最後一行
 sed '2,$d' file      刪除檔案的第2行到末尾所有行
 地址定界:,(逗號)
 sed -n '/test/,/check/p' file     所有在模板test和check所確定的範圍內的行都被列印
 sed -n '5,/^test/p' file          列印從第5行開始到第一個包含以test開始的行之間的所有行:
 sed '/test/,/west/s/$/aaa/' file  模板test和west之間的行,每行的末尾用字串aaa替換
 模式空間:
 sed '1!G;h;$!d' FILE ; sed -n '1!G;h;$p' FILE   倒序輸出(模擬tac)
 sed 'N;D' FILE ; sed '$!d' FILE         輸出檔案最後一行
 sed '$!N;$!D' FILE                      輸出檔案最後2行
 sed 'G' FILE                            給每行結尾新增一行空行
 sed 'g' FILE                            將檔案全部行替換成空行
 sed 'N;s/\n//g' FILE                    將檔案的n和n+1行合併為一行,n為奇數行
 sed ':a;N;$!ba;s/\n//g'                 將檔案所有行合為一行
 sed '/^$/d;G' FILE                      刪除空白行後,給每行結尾新增一行空行
 sed 'n;d' FILE                          刪除偶數行
 sed -n 'p;n' test.txt  #奇數行
 sed -n 'n;p' test.txt  #偶數行
 sed '/test/{ n; s/aa/bb/; }' file 匹配test,移動到下一行,替換aa為bb,並列印該行
 ​
 列印匹配字串的下一行
 grep -A 1 SCC URFILE
 sed -n '/SCC/{n;p}' URFILE
 awk '/SCC/{getline; print}' URFILE
 sed ':a;N;$!ba;s/\n//g' ; sed ':a;$!N;s/\n//g;ta'  將檔案所有行合為一行
 :a         # 建立分支標記
 N          # 讀取下一行追加至模式空間
 $!ba       # 分支到指令碼中帶有標記的地方
 s/\n//g    # 替換\n為空

練習題

1、刪除centos7系統/etc/grub2.cfg檔案中所有以空白開頭的行行首的空白字元

 sed 's#[[:space:]]*##g' /etc/grub2.cfg

2、刪除/etc/fstab檔案中所有以#開頭,後面至少跟一個空白字元的行的行首的#和空白字元

 sed -r s/^#[[:space:]*// /etc/fstab

3、在centos6系統/root/install.log每一行行首增加#號

 sed s/^Installing/#Installing/g /root/install.log

4、在/etc/fstab檔案中不以#開頭的行的行首增加#號

 sed -r "s/(^[^#])*/#\1/" /etc/fstab

5、處理/etc/fstab路徑,使用sed命令取出其目錄名和基名

 基名:echo /etc/fstab | sed -r "s#^(/.*/)([^/]+/?)#\2#"
 目錄名:echo /etc/fstab | sed -r "s#^(/.*/)([^/]+/?)#\1#g"

6、利用sed 取出ifconfig命令中本機的IPv4地址

 ifconfig ens33 |sed -n '2p' | sed -r "s/.*inet[[:space:]]*//" | sed -r "s/[[:space:]]*netmask.*//"

7、統計centos安裝光碟中Package目錄下的所有rpm檔案的以.分隔倒數第二個欄位的重複次數

 ls /run/media/root/CentOS\ 7\ x86_64/Packages/ | grep -v "TBL" |sed -r "s#(.*\.([^.]+).rpm$)#\2#"

8、統計/etc/init.d/functions檔案中每個單詞的出現次數,並排序(用grep和sed兩種方法分別實現)

 grep方法:cat /etc/init.d/functions |grep -io "\<[[:alpha:]]*\>" |sort -rn |uniq -c |sort -n
 sed方法:sed "s/[^[:alpha:]]/\n/g" /etc/init.d/functions" | sort -rn | uniq -c |sort -n

9、將文字檔案的n和n+1行合併為一行,n為奇數行

 sed 'N;s/\n//'

awk

Linux上的實現gawk,文字報告生成器

awk介紹 awk:Aho, Weinberger, Kernighan,報告生成器,格式化文字輸出 有多種版本:New awk(nawk),GNU awk( gawk) gawk:模式掃描和處理語言 基本用法: awk [options] 'program' var=value file… awk [options] -f programfile var=value file… awk [options] 'BEGIN{action;… }pattern{action;… }END{action;… }' file ... awk 程式可由:BEGIN語句塊、能夠使用模式匹配的通用語句塊、END語句塊,共3部分組成 program 通常是被放在單引號中 選項: -F “分隔符” 指明輸入時用到的欄位分隔符 -v var=value 變數賦值

awk語言

 基本格式:awk [options] 'program' file…
 Program:pattern{action statements;..}
 pattern和action
 •pattern部分決定動作語句何時觸發及觸發事件
 BEGIN,END
 •action statements對資料進行處理,放在{}內指明
 print, printf
 分割符、域和記錄
 •awk執行時,由分隔符分隔的欄位(域)標記$1,$2...$n稱為域標識。$0為所有域,注意:此時和shell中變數$符含義不同
 •檔案的每一行稱為記錄
 •省略action,則預設執行 print $0 的操作

awk工作原理

 第一步:執行BEGIN{action;… }語句塊中的語句
 第二步:從檔案或標準輸入(stdin)讀取一行,然後執行pattern{ action;… }語句塊,它逐行掃描檔案,從第一行到最後一行重複這個過程,直到檔案全部被讀取完畢。
 第三步:當讀至輸入流末尾時,執行END{action;…}語句塊
 BEGIN語句塊在awk開始從輸入流中讀取行之前被執行,這是一個可選的語句塊,比如變數初始化、列印輸出表格的表頭等語句通常可以寫在BEGIN語句塊中
 END語句塊在awk從輸入流中讀取完所有的行之後即被執行,比如列印所有行的分析結果這類資訊彙總都是在END語句塊中完成,它也是一個可選語句塊
 pattern語句塊中的通用命令是最重要的部分,也是可選的。如果沒有提供pattern語句塊,則預設執行{ print },即列印每一個讀取到的行,awk讀取的每一行都會執行該語句塊

awk print格式:print item1, item2, ... 要點:

 (1) 逗號分隔符
 (2) 輸出item可以字串,也可是數值;當前記錄的欄位、變數或awk的表示式
 (3) 如省略item,相當於print $0
 示例:
 awk '{print "hello,awk"}'
 awk –F: '{print}' /etc/passwd
 awk –F: ‘{print “wang”}’ /etc/passwd
 awk –F: ‘{print $1}’ /etc/passwd
 awk –F: ‘{print $0}’ /etc/passwd
 awk –F: ‘{print $1”\t”$3}’ /etc/passwd
 grep “^UUID”/etc/fstab | awk ‘{print $2,$4}’

awk變數 變數:內建和自定義變數

 FS:輸入欄位分隔符,預設為空白字元
 awk -v FS=':' '{print $1,FS,$3}’ /etc/passwd
 awk –F: '{print $1,$3,$7}’ /etc/passwd
 OFS:輸出欄位分隔符,預設為空白字元
 awk -v FS=‘:’ -v OFS=‘:’ '{print $1,$3,$7}’ /etc/passwd
 RS:輸入記錄分隔符,指定輸入時的換行符
 awk -v RS=' ' ‘{print }’ /etc/passwd
 ORS:輸出記錄分隔符,輸出時用指定符號代替換行符
 awk -v RS=' ' -v ORS='###'‘{print }’ /etc/passwd
 NF:欄位數量
 awk -F:‘{print NF}’ /etc/fstab 引用變數時,變數前不需加$
 awk -F:‘{print $(NF-1)}' /etc/passwd
 NR:記錄號
 awk ‘{print NR}’ /etc/fstab ; awk END‘{print NR}’ /etc/fstab

 FNR:各檔案分別計數,記錄號
 awk '{print FNR}' /etc/fstab /etc/inittab
 FILENAME:當前檔名
 awk '{print FILENAME}’ /etc/fstab
 ARGC:命令列引數的個數
 awk '{print ARGC}’ /etc/fstab /etc/inittab
 awk ‘BEGIN {print ARGC}’ /etc/fstab /etc/inittab
 ARGV:陣列,儲存的是命令列所給定的各引數
 awk ‘BEGIN {print ARGV[0]}’ /etc/fstab /etc/inittab
 awk ‘BEGIN {print ARGV[1]}’ /etc/fstab /etc/inittab
 自定義變數(區分字元大小寫)
 (1) -v var=value
 (2) 在program中直接定義
 示例:
 awk -v test='hello gawk' '{print test}' /etc/fstab
 awk -v test='hello gawk' 'BEGIN{print test}'
 awk 'BEGIN{test="hello,gawk";print test}'
 awk -F:‘{sex=“male”;print $1,sex,age;age=18}’ /etc/passwd
 cat awkscript
 {print script,$1,$2}
 awk -F: -f awkscript script=“awk” /etc/passwd
 printf命令
 格式化輸出:printf “FORMAT”, item1, item2, ...
 (1) 必須指定FORMAT
 (2) 不會自動換行,需要顯式給出換行控制符,\n
 (3) FORMAT中需要分別為後面每個item指定格式符
 格式符:與item一一對應
 %c:顯示字元的ASCII碼
 %d, %i:顯示十進位制整數
 %e, %E:顯示科學計數法數值
 %f:顯示為浮點數
 %g, %G:以科學計數法或浮點形式顯示數值
 %s:顯示字串
 %u:無符號整數
 %%:顯示%自身
 修飾符

 #[.#] 第一個數字控制顯示的寬度;第二個#表示小數點後精度,%3.1f
 - 左對齊(預設右對齊) %-15s
 + 顯示數值的正負符號 %+d
 printf示例
 awk -F: ‘{printf "%s",$1}’ /etc/passwd
 awk -F: ‘{printf "%s\n",$1}’ /etc/passwd
 awk -F: '{printf "%-20s %10d\n",$1,$3}' /etc/passwd
 awk -F:‘ {printf "Username: %s\n",$1}’ /etc/passwd
 awk -F: ‘{printf “Username: %s,UID:%d\n",$1,$3}’ /etc/passwd
 awk -F: ‘{printf "Username: %15s,UID:%d\n",$1,$3}’ /etc/passwd
 awk -F: ‘{printf "Username: %-15s,UID:%d\n",$1,$3}’ /etc/passwd
 操作符
 算術操作符:
 x+y, x-y, x*y, x/y, x^y, x%y
 - x:轉換為負數
 +x:將字串轉換為數值
 字串操作符:沒有符號的操作符,字串連線
 賦值操作符:
 =, +=, -=, *=, /=, %=, ^=,++, --
 下面兩語句有何不同
 •awk ‘BEGIN{i=0;print ++i,i}’
 •awk ‘BEGIN{i=0;print i++,i}’

操作符

 比較操作符:
 ==, !=, >, >=, <, <=
 模式匹配符:
 ~:左邊是否和右邊匹配,包含
 !~:是否不匹配
 示例:
awk -F: '$0 ~ /root/{print $1}‘ /etc/passwd
 awk '$0~“^root"' /etc/passwd
 awk '$0 !~ /root/‘ /etc/passwd
 awk -F: ‘$3==0’ /etc/passwd
 邏輯操作符:與&&,或||,非!
 示例:
 •awk -F: '$3>=0 && $3<=1000 {print $1}' /etc/passwd
 •awk -F: '$3==0 || $3>=1000 {print $1}' /etc/passwd
 •awk -F: ‘!($3==0) {print $1}' /etc/passwd
 •awk -F: ‘!($3>=500) {print $3}’ /etc/passwd

 條件表示式(三目表示式)
 selector?if-true-expression:if-false-expression
 •示例:
 awk -F: '{$3>=1000?usertype="Common User":usertype=" SysUser";printf "%15s:%-s\n",$1,usertype}' /etc/passwd
 PATTERN:根據pattern條件,過濾匹配的行,再做處理
 (1)如果未指定:空模式,匹配每一行
 (2) /regular expression/:僅處理能夠模式匹配到的行,需要用/ /括起來
 awk '/^UUID/{print $1}' /etc/fstab
 awk '!/^UUID/{print $1}' /etc/fstab
 (3) relational expression: 關係表示式,結果為“真”才會被處理
 真:結果為非0值,非空字串
 假:結果為空字串或0值
 示例:
 awk -F: 'i=1;j=1{print i,j}' /etc/passwd
 awk ‘!0’ /etc/passwd ; awk ‘!1’ /etc/passwd
 Awk -F: '$3>=1000{print $1,$3}' /etc/passwd
 awk -F: '$3<1000{print $1,$3}' /etc/passwd
 awk -F: '$NF=="/bin/bash"{print $1,$NF}' /etc/passwd
 awk -F: '$NF ~ /bash$/{print $1,$NF}' /etc/passwd

awk PATTERN

  line ranges:行範圍
 startline,endline:/pat1/,/pat2/ 不支援直接給出數字格式
 awk -F: ‘/^root\>/,/^nobody\>/{print $1}' /etc/passwd
 awk -F: ‘(NR>=10&&NR<=20){print NR,$1}' /etc/passwd
 BEGIN/END模式
 BEGIN{}:僅在開始處理檔案中的文字之前執行一次
 END{}:僅在文字處理完成之後執行一次

 awk -F : ‘BEGIN {print “USER USERID”} {print $1“:”$3}
 END{print “END FILE"}' /etc/passwd
 awk -F : '{print "USER USERID“;print $1":"$3} END{print "END FILE"}' /etc/passwd
 awk -F: 'BEGIN{print " USER UID \n--------------- "}{print $1,$3}' /etc/passwd
 awk -F: ‘BEGIN{print “ USER UID \n--------------- ”}{print $1,$3}’END{print “==============”} /etc/passwd
 seq 10 | awk 'i=0'
 seq 10 | awk 'i=1'
 seq 10 | awk 'i=!i'
 seq 10 | awk '{i=!i;print i}'
 seq 10 | awk ‘!(i=!i)'
 seq 10 |awk -v i=1 'i=!i'

awk action 常用的action分類

 (1) Expressions:算術,比較表示式等
 (2) Control statements:if, while等
 (3) Compound statements:組合語句
 (4) input statements
 (5) output statements:print等

awk控制語句

 { statements;… } 組合語句
 if(condition) {statements;…}
 if(condition) {statements;…} else {statements;…}
 while(conditon) {statments;…}
 do {statements;…} while(condition)
 for(expr1;expr2;expr3) {statements;…}
 break
 continue
 delete array[index]
 delete array
 exit

awk控制語句if-else 語法:if(condition){statement;…}[else statement] if(condition1){statement1}else if(condition2){statement2}else{statement3} 使用場景:對awk取得的整行或某個欄位做條件判斷 示例:

 awk -F: '{if($3>=1000)print $1,$3}' /etc/passwd
 awk -F: '{if($NF=="/bin/bash") print $1}' /etc/passwd
 awk '{if(NF>5) print $0}' /etc/fstab
 awk -F: '{if($3>=1000) {printf "Common user: %s\n",$1} else {printf "root or Sysuser: %s\n",$1}}' /etc/passwd
 awk -F: '{if($3>=1000) printf "Common user: %s\n",$1; else printf "root or Sysuser: %s\n",$1}' /etc/passwd
 df -h|awk -F% '/^\/dev/{print $1}'|awk '$NF>=80{print $1,$5}‘
 awk ‘BEGIN{ test=100;if(test>90){print “very good“}
 else if(test>60){ print ”good”}else{print “no pass”}}’

while迴圈 語法:while(condition){statement;…} 條件“真”,進入迴圈;條件“假”,退出迴圈 使用場景: 對一行內的多個欄位逐一類似處理時使用 對陣列中的各元素逐一處理時使用 示例:

 awk '/^[[:space:]]*linux16/{i=1;while(i<=NF)
 {print $i,length($i); i++}}' /etc/grub2.cfg
 awk ‘/^[[:space:]]*linux16/{i=1;while(i<=NF) {if(length($i)>=10) {print $i,length($i)}; i++}}’ /etc/grub2.cfg
 [root@shell ~]# echo I am oldboy teacher welcome to oldboy training class|awk '{for(i=1;i<=NF;i++){if (length($i)<=6) {print $i}}}' 
 I
 am
 oldboy
 to
 oldboy
 class
 do-while迴圈
 語法:do {statement;…}while(condition)
 意義:無論真假,至少執行一次迴圈體
 示例:
 awk 'BEGIN{ total=0;i=0;do{ total+=i;i++;}while(i<=100);print total}’
 for迴圈
 語法:for(expr1;expr2;expr3) {statement;…}
 常見用法:
 for(variable assignment;condition;iteration process)
 {for-body}

 特殊用法:能夠遍歷陣列中的元素
 語法:for(var in array) {for-body}
 示例:
 awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {print $i,length($i)}}' /etc/grub2.cfg
 效能比較
 time (awk 'BEGIN{ total=0;for(i=0;i<=10000;i++){total+=i;};print total;}')
 time(total=0;for i in {1..10000};do total=$(($total+i));done;echo $total)
 time(for ((i=0;i<=10000;i++));do let total+=i;done;echo $total)
 time(seq –s ”+” 10000|bc)
 switch語句
 語法:switch(expression) {case VALUE1 or /REGEXP/: statement1; case VALUE2 or /REGEXP2/: statement2; ...; default: statementn}
 break和continue
 awk ‘BEGIN{sum=0;for(i=1;i<=100;i++)
 {if(i%2==0)continue;sum+=i}print sum}'
 awk ‘BEGIN{sum=0;for(i=1;i<=100;i++)
 {if(i==66)break;sum+=i}print sum}'

 break [n]
 continue [n]
 next:
提前結束對本行處理而直接進入下一行處理(awk自身迴圈)
 awk -F: '{if($3%2!=0) next; print $1,$3}' /etc/passwd

awk陣列 關聯陣列:array[index-expression] index-expression:

 (1) 可使用任意字串;字串要使用雙引號括起來
 (2) 如果某陣列元素事先不存在,在引用時,awk會自動建立此元素,並將其值初始化為“空串”
 (3) 若要判斷陣列中是否存在某元素,要使用“index in array”格式進行遍歷
 示例:
 weekdays["mon"]="Monday"
 awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";
 print weekdays["mon"]}‘
 awk '!line[$0]++' dupfile
 awk '{!line[$0]++;print $0, line[$0]}' dupfile

 若要遍歷陣列中的每個元素,要使用for迴圈
 for(var in array) {for-body}
 注意:var會遍歷array的每個索引
 示例: awk‘BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday"; for(i in weekdays) {print weekdays[i]}}'
 netstat -tan | awk '/^tcp/{state[$NF]++}
 END{for(i in state) { print i,state[i]}}'
 awk '{ip[$1]++}END{for(i in ip) {print i,ip[i]}}' /var/log/httpd/access_log

 數值處理:
 rand():返回0和1之間一個隨機數
 awk 'BEGIN{srand(); for (i=1;i<=10;i++)print int(rand()*100) }'
 字串處理:
 length([s]):返回指定字串的長度
 sub(r,s,[t]):對t字串搜尋r表示模式匹配的內容,並將第一個匹配內容替換為s
 echo "2008:08:08 08:08:08" | awk 'sub(/:/,"-",$1)'
 echo "2008:08:08 08:08:08" | awk '{sub(/:/,"-",$1);print $0}'
 •gsub(r,s,[t]):對t字串進行搜尋r表示的模式匹配的內容,並全部替換為s所表示的內容
 echo "2008:08:08 08:08:08" | awk 'gsub(/:/,"-",$0)'
 echo "2008:08:08 08:08:08" | awk '{gsub(/:/,"-",$0);print $0}'
 •split(s,array,[r]):以r為分隔符,切割字串s,並將切割後的結果儲存至array所表示的陣列中,第一個索引值為1,第二個索引值為2,…
 netstat -tn | awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++}
 END{for (i in count) {print i,count[i]}}’

 數值處理:
 rand():返回0和1之間一個隨機數
 awk 'BEGIN{srand(); for (i=1;i<=10;i++)print int(rand()*100) }'
 字串處理:
 •length([s]):返回指定字串的長度
 •sub(r,s,[t]):對t字串搜尋r表示模式匹配的內容,並將第一個匹配內容替換為s
 echo "2008:08:08 08:08:08" | awk 'sub(/:/,"-",$1)'
 echo "2008:08:08 08:08:08" | awk '{sub(/:/,"-",$1);print $0}'
 •gsub(r,s,[t]):對t字串進行搜尋r表示的模式匹配的內容,並全部替換為s所表示的內容
 echo "2008:08:08 08:08:08" | awk 'gsub(/:/,"-",$0)'
 echo "2008:08:08 08:08:08" | awk '{gsub(/:/,"-",$0);print $0}'
 •split(s,array,[r]):以r為分隔符,切割字串s,並將切割後的結果儲存至array所表示的陣列中,第一個索引值為1,第二個索引值為2,…
 netstat -tn | awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++}
 END{for (i in count) {print i,count[i]}}’

awk函式 自定義函式格式:

 function name ( parameter, parameter, ... ) {
 statements
 return expression
 }
 示例:
 cat fun.awk
 function max(x,y) {
 x>y?var=x:var=y
 return var
 }
 BEGIN{a=3;b=2;print max(a,b)}
 awk -f fun.awk

 awk中呼叫shell命令
 system命令
 空格是awk中的字串連線符,如果system中需要使用awk中的變數可以使用空格分隔,或者說除了awk的變數外其他一律用""引用起來
 awk 'BEGIN{system("hostname") }'
 awk 'BEGIN{score=100; system("echo your score is " score) }'

awk指令碼

將awk程式寫成指令碼,直接呼叫或執行 示例:

 cat f1.awk
 {if($3>=1000)print $1,$3}
 awk -F: -f f1.awk /etc/passwd
 cat f2.awk
 #!/bin/awk –f
 #this is a awk script
 {if($3>=1000)print $1,$3}
 chmod +x f2.awk
 f2.awk –F: /etc/passwd

 向awk指令碼傳遞引數
 格式:
 awkfile var=value var2=value2... Inputfile
 注意:在BEGIN過程中不可用。直到首行輸入完成以後,變數才可用。可以通過-v 引數,讓awk在執行BEGIN之前得到變數的值。命令列中每一個指定的變數都需要一個-v引數
 示例:
 cat test.awk
 #!/bin/awk –f
 {if($3 >=min && $3<=max)print $1,$3}
 chmod +x test.awk
 test.awk -F: min=100 max=200 /etc/passwd

 

awk補充

awk [options] -f progfile [var=value] file ...
 awk [options] [var=value] 'program' file ...
 POSIX options:  GNU long options: (standard)
     -f progfile --file=progfile           從指令碼檔案中讀取awk命令
     -F fs       --field-separator=fs      指定分隔符,fs是一個字串或正規表示式
     -v var=val  --assign=var=val          賦值一個自定義變數
 Short options:  GNU long options: (extensions)
     -b          --characters-as-bytes     將所有輸入資料視為單位元組字元(--posix覆蓋這個選項)
     -c          --traditional             在相容模式下執行,awk=gawk
     -d[file]    --dump-variables[=file]   列印已排序的全域性變數列表,沒有 file 列印幫助
     -e 'program-text'   --source='program-text'  使用 program-text 作為AWK程式原始碼
     -g          --gen-pot                 掃描並解析AWK程式,生成一個GNU.pot
     可移植物件模板)格式的檔案
     -n          --non-decimal-data        識別輸入資料中的八進位制和十六進位制值
     -r          --re-interval             在正規表示式匹配中啟用間隔表示式的使用 

 awk內建變數:
 $n            當前記錄的第n個欄位,欄位間由FS分隔
 $0            完整的輸入記錄
 ARGC          命令列引數的數目
 ARGIND        命令列中當前檔案的位置(從0開始算)
 ARGV          包含命令列引數的陣列
 CONVFMT       數字轉換格式(預設值為%.6g)
 ENVIRON       環境變數關聯陣列
 ERRNO         最後一個系統錯誤的描述
 FIELDWIDTHS   欄位寬度列表(用空格鍵分隔)
 FILENAME      當前檔名
 FNR           各檔案分別計數的行號
 FS            欄位分隔符(預設是任何空格)
 IGNORECASE    如果為真,則進行忽略大小寫的匹配
 NF            一條記錄的欄位的數目
 NR            已經讀出的記錄數,就是行號,從1開始
 OFMT          數字的輸出格式(預設值是%.6g)
 OFS           輸出記錄分隔符(輸出換行符),輸出時用指定的符號代替換行符
 ORS           輸出記錄分隔符(預設值是一個換行符)
 RLENGTH       由match函式所匹配的字串的長度
 RS            記錄分隔符(預設是一個換行符)
 RSTART        由match函式所匹配的字串的第一個位置
 SUBSEP        陣列下標分隔符(預設值是/034)

 = += -= *= /= %= ^= **=    賦值
 ?:                         C條件表示式
 ||                         邏輯或
 &&                         邏輯與
 ~ 和 !~                    匹配正規表示式和不匹配正規表示式
 < <= > >= != ==            關係運算子
 空格                        連線
 + -                        加,減
 * / %                      乘,除與求餘
 + - !                      一元加,減和邏輯非
 ^                          求冪
 ++ --                      增加或減少,作為字首或字尾
 $                          欄位引用
 in                         陣列成員

 條件語句
 if (expression) {
     statement;
     statement;
     ... ...
 }
 ​
 if (expression) {
     statement;
 } else {
     statement2;
 }
 ​
 if (expression) {
     statement1;
 } else if (expression1) {
 statement2;
 } else {
     statement3;
 }
 迴圈語句
 C語言:while、do/while、for、break、continue
 Examples:
 一.命令列方式呼叫awk
 awk [-F  field-separator]  'commands'  input-file(s)
 1 搜尋/etc/passwd有root關鍵字的所有行
 awk -F: '/root/' /etc/passwd
 2 搜尋/etc/passwd有root關鍵字的所有行,並顯示對應的shell
 awk -F: '/root/{print $7}' /etc/passwd
 3 列印/etc/passwd 中以:為分隔符分割的每行第一項
 awk -F: '{ print $1 }' /etc/passwd
 4 使用","分割,-F相當於內建變數FS, 指定分隔符
 awk -F, '{print $1,$2}' filename
 awk 'BEGIN{FS=","} {print $1,$2}' filename
 5 使用多個分隔符:先使用空格分割,然後對分割結果再使用","分割
 awk -F '[ ,]' '{print $1,$2,$5}' filename
 6 統計 file 行數
 awk '{ sum += $1 }; END { print sum }' file
 7 統計使用者個數
 awk '{count++;print $0;} END{print "user count is ",count}' /etc/passwd  
 8 行匹配語句 awk '' 只能用單引號
 awk '{[pattern] action}' {filenames}
 9 每行輸出文字中的1、4項,按空格或TAB分割
 awk '{print $1,$4}' filename
 10 格式化每行輸出文字中的1、4項,按空格或TAB分割
 awk '{printf "%-8s %-10s\n",$1,$4}' filename   
 11 設定變數a=1,b=s,每行輸出文字中的1項、1項+a(數字求和,非數字直接是a)、1項新增字尾b,按空格或TAB分割
 awk -va=1 -vb=s '{print $1,$1+a,$1b}' filename 
 12 檢視filename檔案內第20到第30行的所有內容
 awk '{if(NR>=20 && NR<=30) print $0}' filename 
 13 統計當前目錄下檔案總大小,以M為單位輸出
 ll |awk 'BEGIN{size=0;} {size=size+$5;} END{print "[end]size is ",size/1024/1024,"M"}'  
 14 顯示/etc/passwd的賬戶,for迴圈遍歷陣列
 awk -F ':' 'BEGIN {count=0;} {name[count] = $1;count++;}; END{for (i = 0; i < NR; i++) print i, name[i]}' /etc/passwd
 15 按降序排序,篩選第二行小於70,統計總數(行數)
 sort -rnk2 1.txt|awk '$2<70'|wc-l
 二.shell指令碼方式
 #!/bin/awk -f
 BEGIN{ 這裡面放的是執行前的語句 }
 {這裡面放的是處理每一行時要執行的語句}
 END {這裡面放的是處理完所有的行後要執行的語句 }
 三.將所有的awk命令插入一個單獨檔案,然後呼叫
 awk -f awk-script-file input-file(s)

gsub函式的用法

 sub匹配第一次出現的符合模式的字串,相當於 sed 's//'   
 gsub匹配所有的符合模式的字串,相當於 sed 's//g'  
 例如:
 awk '{sub(/Mac/,"Macintosh");print}' urfile    用Macintosh替換Mac
 awk '{sub(/Mac/,"MacIntosh",$1); print}' file    第一個域內用Macintosh替換Mac
 把上面sub換成gsub就表示在滿足條件得域裡面替換所有的字元。
 awk的sub函式用法:
 sub函式匹配指定域/記錄中最大、最靠左邊的子字串的正規表示式,並用替換字串替換這些字串。
 如果沒有指定目標字串就預設使用整個記錄。替換隻發生在第一次匹配的時候。格式如下:
 sub (regular expression, substitution string):
 sub (regular expression, substitution string, target string)
 例項:
 $ awk '{ sub(/test/, "mytest"); print }' testfile
 $ awk '{ sub(/test/, "mytest", $1); print }' testfile
 第一個例子在整個記錄中匹配,替換隻發生在第一次匹配發生的時候。
 第二個例子在整個記錄的第一個域中進行匹配,替換隻發生在第一次匹配發生的時候。
 如要在整個檔案中進行匹配需要用到gsub
 gsub函式作用如sub,但它在整個文件中進行匹配。格式如下:
gsub (regular expression, substitution string)
 gsub (regular expression, substitution string, target string)

 例項:
 $ awk '{ gsub(/test/, "mytest"); print }' testfile
 $ awk '{ gsub(/test/, "mytest", $1); print }' testfile
       第一個例子在整個文件中匹配test,匹配的都被替換成mytest。
       第二個例子在整個文件的第一個域中匹配,所有匹配的都被替換成mytest。
 另外, 只有當記錄中的域有改變的時候 ,指定0FS變數才有用, 如果記錄中的域無變化, 指定OFS產生不了實際效果。

 awk -F'|' -v OFS='|' '{ gsub(/[0-9]/, "", $3); print $0; }' data.txt   
 將把第三個域中所有數字都去掉。
 
另外,對於數字的匹配,可以使用十六進位制。
​
 awk -F'|' -v OFS='|' '{ gsub(/[/x30-/x39]/, "", $3); print $0; }' data.txt 

基本正規表示式 BRE 元字元

 字元匹配:
 .            匹配任意單個字元
 []           匹配指定範圍內的任意單個字元,示例:[wang] [0-9] [a-z] [a-zA-Z]
 [^]          匹配指定範圍外的任意單個字元
 匹配次數:
 用在要指定次數的字元後面,用於指定前面的字元要出現的次數
 *         匹配前面的字元任意次,包括0次,貪婪模式:儘可能長的匹配
  .*        任意長度的任意字元
  \?        匹配其前面的字元0或1次
  \+        匹配其前面的字元至少1次
  \{n\}     匹配前面的字元n次
  \{m,n\}   匹配前面的字元至少m次,至多n次
  \{,n\}    匹配前面的字元至多n次
 \{n,\}    匹配前面的字元至少n次
 匹配次數:
 用在要指定次數的字元後面,用於指定前面的字元要出現的次數
  *         匹配前面的字元任意次,包括0次,貪婪模式:儘可能長的匹配
  .*        任意長度的任意字元
  \?        匹配其前面的字元0或1次
  \+        匹配其前面的字元至少1次
  \{n\}     匹配前面的字元n次
  \{m,n\}   匹配前面的字元至少m次,至多n次
  \{,n\}    匹配前面的字元至多n次
  \{n,\}    匹配前面的字元至少n次
 -  位置錨定:
 定位出現的位置
 ^               行首錨定,用於模式的最左側
 $               行尾錨定,用於模式的最右側
 ^PATTERN$       用於模式匹配整行
 ^$              空行
 ^[[:space:]]*$  空白行
 \< 或 \b        詞首錨定,用於單詞模式的左側
 \> 或 \b        詞尾錨定,用於單詞模式的右側
 \<PATTERN\>     匹配整個單詞
 \w              某個單詞
 分組:\(\) 
 將一個或多個字元捆綁在一起,當作一個整體處理,如:\(root\)\+
 分組括號中的模式匹配到的內容,會被正規表示式引擎記錄於內部的變數中,
 這些變數的命名方式為: \1, \2, \3, ...
 示例:
 \(string1\(string2\)\)
 \1 :string1\(string2\)  # 表示從左側起第一個左括號以及與之匹配右括號之間的模式所匹配到的字元。
 \2 :string2
 後向引用:引用前面的分組括號中的模式所匹配字元,而非模式本身
 ​
 或:\|
 示例:a\|b        a或b
      C\|cat      C或cat
      \(C\|c\)at  Cat或ca
 字元匹配:
 .   任意單個字元
 []  指定範圍的字元
 [^] 不在指定範圍的字元
 次數匹配:
 *     匹配前面字元任意次
 ?     0或1次
 +     1次或多次
 {m}   匹配m次
 {m,n} 至少m,至多n次
 *     匹配前面字元任意次
 ?     0或1次
 +     1次或多次
 {m}   匹配m次
 {m,n} 至少m,至多n次
 位置錨定:
 ^      行首
 $      行尾
 \<, \b 語首
 \>, \b 語尾
 \w     單詞
 分組:()
 ​
 後向引用:\1, \2, ...
 ​
 或:
 a|b      a或b
 C|cat    C或cat
 (C|c)at  Cat或cat
 特殊字符集
 字符集需要用 [ ] 來包含住,否則不會生效
 [:alnum:]    字母和數字
 [:alpha:]    代表任何英文大小寫字元,亦即 A-Z, a-z
 [:lower:]    小寫字母 
 [:upper:]    大寫字母
 [:blank:]    空白字元(空格和製表符)
 [:space:]    水平和垂直的空白字元(比[:blank:]包含的範圍廣)
 [:cntrl:]    不可列印的控制字元(退格、刪除、警鈴...)
 [:digit:]    十進位制數字 
 [:xdigit:]   十六進位制數字
 [:graph:]    可列印的非空白字元
 [:print:]    可列印字元
 [:punct:]    標點符號
 *                 匹配任意零個或多個字元
 ?                 匹配任意一個字元
 [0-9]             匹配任意數字
 [a-z]             匹配任意小寫字母
 [A-Z]             匹配任意大寫字母
 []                匹配中括號裡任意一個字元,- 指定範圍
 [^] ; [!]         匹配中括號裡任意字元以外的字元,取反
 大括號擴充套件
 &>>file    把 標準輸出 和 標準錯誤 都追加重定向到file

練習題:

1、檔案ip_list.txt如下格式,請提取”.magedu.com”前面的主機名部分並寫入到回到該檔案中 1 blog.magedu.com 2 www.magedu.com 999 study.magedu.com

 [root.CentOS 7] ~ awk -F. '{print $1}' ip-list.txt >> ip-list.txt

2、統計/etc/fstab檔案中每個檔案系統型別出現的次數

 [root.CentOS 7] ➤ awk '/^[^#].*$/{print $3}' /etc/fstab |sort|uniq -c

3、統計/etc/fstab檔案中每個單詞出現的次數

 [root.CentOS 7] ➤ awk 'gsub(/[^[:alpha:]]/,"\n",$0)' /etc/fstab | sort|uniq -c

4、提取出字串Yd$C@M05MB%9&Bdh7dq+YVixp3vpw中的所有數字

 [root.CentOS 7] ➤ echo "Yd$C@M05MB%9&Bdh7dq+YVixp3vpw" | awk 'gsub(/[^[:digit:]]/,"",$0)'

5、有一檔案記錄了1-100000之間隨機的整數共5000個,儲存的格式100,50,35,89…請取出其中最大和最小的整數

 awk -F, '{if($1>$2){big=$1;small=$2}\
 else{big=$2;small=$1}\
 for(i=3;i<=NF;i++){\
 if(big<$i){big=$i}\
 if(small>$i){small=$i}\
 }}\
 END{print "big:"big"\nsmall:"small}' RANDOM.txt

6、解決DOS攻擊生產案例:根據web日誌或者或者網路連線數,監控當某個IP併發連線數或者短時內PV達到100,即呼叫防火牆命令封掉對應的IP,監控頻率每隔5分鐘。防火牆命令為:iptables -A INPUT -s IP -j REJECT

 >crontab -e
 */5 * * * * bash dos.sh
 >cat dos.sh
 #!/bin/bash
 ss -t | awk -F "[[:space:]]+|:" '{count[$6]++;}END{for(i in count){if(count[i]>1){system("iptables  -A INPUT -s " i " -j REJECT")}}}'

7、將以下檔案內容中FQDN取出並根據其進行計數從高到低排序

http://mail.magedu.com/index.html
http://www.magedu.com/test.html
http://study.magedu.com/index.html
http://blog.magedu.com/index.html
http://www.magedu.com/images/logo.jpg
http://blog.magedu.com/20080102.html
[root.CentOS 7] ➤ awk -F "[/|.]" '{count[$3]++}END{for(i in count){print i,count[i]}}' url.txt

8、將以下文字以inode為標記,對inode相同的counts進行累加,並且統計出同一inode中,beginnumber的最小值和endnumber的最大值

 inode|beginnumber|endnumber|counts| 106|3363120000|3363129999|10000| 106|3368560000|3368579999|20000| 
310|3337000000|3337000100|101| 310|3342950000|3342959999|10000| 310|3362120960|3362120961|2|
311|3313460102|3313469999|9898| 311|3313470000|3313499999|30000| 311|3362120962|3362120963|2|
輸出的結果格式為: 310|3337000000|3362120961|10103| 311|3313460102|3362120963|39900| 106|3363120000|3368579999|30000| awk -F "|" -v OFS="|" 'NR==1{print $0}\ NR>1{count[$1]+=$4;if(max[$1]<$3){max[$1]=$3}\ if(!min[$1]){min[$1]=$2}if(min[$i]>$2){min[$1]=$2}}\ END{for(i in count){print i,min[i],max[i],count[i]"|"}}' inode.txt

 

 





相關文章