shell知識點(8)AWK命令詳解
阿新 • • 發佈:2020-09-14
AWK介紹
awk(名字來源於三個創始人姓氏首字母)是linux系統下文字編輯工具,是一門程式語言,有自己的基本語法和流程控制、函式。awk簡單高效。
呼叫AWK
1.命令列方式 awk [-F field-separator] 'commands' input-file(s) 其中,commands 是真正awk命令,[-F域分隔符]是可選的。 input-file(s) 是待處理的檔案。 在awk中,檔案的每一行中,由域分隔符分開的每一項稱為一個域。通常,在不指名-F域分隔符的情況下,預設的域分隔符是空格。 2.shell指令碼方式 將所有的awk命令插入一個檔案,並使awk程式可執行,然後awk命令直譯器作為指令碼的首行,一遍通過鍵入指令碼名稱來呼叫。 相當於shell指令碼首行的:#!/bin/sh 可以換成:#!/bin/awk 3.將所有的awk命令插入一個單獨檔案,然後呼叫: awk -f awk-script-file input-file(s) 其中,-f選項載入awk-script-file中的awk指令碼,input-file(s)跟上面的是一樣的。
=========================================================================================================================
一、AWK基本語法
awk通過FS作為每一段文字的分割符(預設空格),在命令列上可以用-F引數指定分隔符; 通過RS$0 當前所有欄位 $1--$n 按照分隔符分割取到的第n列內容 FS 分隔符(預設空格) awk 'BEGIN{FS=":"}{print $1}' /etc/passwd ;等價於awk -F: '{print $1}' /etc/passwd RS 換行符(預設回車) awk 'BEGIN{RS=":"}{print $1}' /etc/passwd NF 字元列數,當前處理行的分割後的列數 awk -F: '{print NF}' /etc/passwd NR 行號 awk -F: '{print NR ":" $1}' /etc/passwd OFS (預設空格)輸出欄位分隔符 ORS (預設回車)輸出記錄分隔符
ARGC 命令列引數個數 ARGV 命令列引數排列 ENVIRON 支援佇列中系統環境變數的使用 FILENAME awk瀏覽的檔名 FNR 瀏覽檔案的記錄數 FS 設定輸入域分隔符,等價於命令列 -F選項
自定義外部變數
-v:自定義變數
awk -v host=$HOSTNAME "BEGIN{print host}"
關係操作符
<、>、<=、>=、==、!=、~、!~ 比較符<等與其他的語言類似,重點說一下不一樣的 ~:用來判斷前面的列是否匹配後面的內容。例如awk -F: '$7 ~ /^\/bin/{print $0}' /etc/passwd(判斷第7列是否以/bin開頭,如果是列印該列) !~:不匹配
輸出print和printf
print:直接輸出 awk -F: '{print $1 ":" $2}' /etc/passwd printf:格式化輸出(printf是一個函式,需要用到()) awk -F: '{printf(hello %s:%s\n),$1,$2}' 注意:printf需要手動增加\n來換行。使用%s來格式化,printf()外加入要替換的變數
二、AWK的流程控制
條件:
if語句 if(expression){action1}else{action2} 例如:產生10個數seq 10,通過if語句判斷是單數還是雙數 seq 10 |awk '{if($0%2==0){print $0"是雙數"}else{print $0"是單數"}}' 如果只需要一個if分支,可以省略前面的if,比如awk -F: '$3<-10 {print $1}' /etc/passwd迴圈:
while語句:while(expression){action} 例子:使用:分割/etc/passwd,並將每一列前加上列號 awk -F: '{i=1;while(i<=NF){print i":"$i;i++ }}' /etc/passwd
for語句: 第一種方法:for(i=0;i<=10;i++){action} 例子:使用:分割/etc/passwd,並將每一列前加上列號 awk -F: '{for(i=1;i<=NF;i++){print i":"$i}}' /etc/passwd 第二種方法:for(value in array){action} 當value在array的key中,進行下面的操作。awk的陣列類似python中的字典。 例子:統計/etc/passwd第7列的值及對應的個數 awk -F: '{a[$7]++}END{for(i in a)if(i!=""){print i":"a[i]}}' /etc/passwd 說明:a[$7]:將$7作為陣列a的key,然後統計對應的個數;然後遍歷for(i in a),判斷i是否在陣列a的key中;如果存在則列印a[i],a[i]為對應key的值,這裡指個數。陣列:
array[1]="hello" array["name"]="Jack" 陣列類似python的字典,array[key值]="value值";key為索引,可以是數字也可以是字串。 陣列元素的刪除:delete array["key"] 例子:定義了陣列a的三個值,並列印結果檢視 awk 'BEGIN{a[1]="hello";a[2]="word";a["name"]="meitian";for(i in a){print "key為"i":value為"a[i]}}'
三、awk函式
內建函式 1.算術函式:int(x) 返回x的整數部分的值,值不會四捨五入,只是取整 sqrt(x) 返回x的平方根 rand() 返回偽隨機數r,其中0<=r<1,(偽隨機數指返回的值都是上一次返回的同一個隨機數) srand(x) 建立rand()新的種子數,如果沒有指定就用當天的時間(使用srand()可以使得rand()返回不同的隨機數) 例子:rand()產生一個隨機數,通過srand()產生新的種子數,然後再差生一個隨機數 awk 'BEGIN{print rand();srand();print rand()}'2.字串函式:
sub("要替換的字串","替換後的字串值"):替換匹配到的第一個文字 echo "hello world world" | awk '{sub("world","meitian");print $0}' gsub("要替換的字串","替換後的字串值" ):開啟全域性替換,替換文字中所有匹配到的字串 echo "hello world world" | awk '{gsub("world","meitian");print $0}'
示例:
[root@t-enter ~]# echo "hello world world" | awk '{gsub("world","meitian");print $0}' hello meitian meitian [root@t-enter ~]# echo "hello world world" | awk '{sub("world","meitian");print $0}' hello meitian world
index("a","b"):返回字串b在字串a中開始的位置 awk 'BEGIN{print index("hello world","world")}' length("s"):返回字串s的長度,當沒有指定s時,返回$0的長度 awk -F 'BEGIN{print length("hello world")}{print lenght()}' /etc/passwd match("s","r"):如果正則表示式r在s中匹配到,則返回出現的起始位置,否則返回0 awk 'BEGIN{print match("hello world","[wo]")}' split(s,a,sep) 使用sep將字串s分解到陣列a中,預設sep為FS。
例子:使用o做為分隔符,將"hello world"進行分割儲存到陣列a中 awk 'BEGIN{print split("hello world",a,"o");for(i in a){print a[i]}}' [root@t-enter ~]# awk 'BEGIN{print split("hello world",a,"o");for(i in a){print a[i]}}' 3 hell w rld
toupper(s):將所有小寫字母轉換成大寫字母 echo "hello world" |awk '{print toupper($0)}' tolower(s):將所有大寫字母轉換成小寫字母 echo "HELLO WORLD" |awk '{print tolower($0)}'自定義函式:
function 函式名(引數1,引數2,...){語句;return 表示式} 例子:求和 awk 'function sum(a,b){total=a+b;return total}BEGIN{print sum(2,3)}' 注意:函式必須寫在BEGIN{}{}END{}的花括號之外的地方,不能放在任何{}內,否則會報錯`return' used outside function context
四、實戰
1.獲得eth0的IP地址ifconfig eth0 | awk -F":| +" '/inet addr:/{print $4}'
ifconfig eth0的結果:
[root@t-enter ~]# ifconfig eth0 eth0 Link encap:Ethernet HWaddr 00:0C:29:F3:13:BB inet addr:192.168.174.5 Bcast:192.168.174.255 Mask:255.255.255.0 inet6 addr: fe80::20c:29ff:fef3:13bb/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:1531377 errors:0 dropped:0 overruns:0 frame:0 TX packets:288458 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:1593454324 (1.4 GiB) TX bytes:24880369 (23.7 MiB) Interrupt:19 Base address:0x2000
說明:
1.多個字元作為分隔符(比如例子中的冒號和空格),可以使用|來區分;或者直接使用正則來作區分。比如例子中的-F":| +"可以寫成-F"[ :]+" 2.如果要過濾多個相同分隔符,可以使用正則的+。表示1個或多個 3.awk中可以使用'/操作匹配到該內容的行/{匹配到前面的行後進行的操作}'來選擇某些想要的行。比如例子中需要取匹配到“inet addr:”的行,列印第4列,//中的為正則表示式,如果有/等需要使用\進行轉義 2.統計tcp網路連線數netstat -an |awk '/^tcp/{a[$NF]++}END{for(i in a){printf("%s:%d\n",i,a[i])}}'說明:與上面的例子大同小異,/^tcp/表示只處理以tcp開頭的行。$NF表示最後一列
五、在實戰中可能用到的注意點
1.awk需要對檔案進行處理。不需要處理檔案的可以把列印命令寫在BEGIN裡(例如:awk -v name=meitian 'BEGIN{print name}') 2.可以對ls等命令結果進行處理 例子:對包含conf的檔案按照.進行分割,並將分割結果用冒號進行連線 ls |grep conf |awk -F. '{print $1 ":" $2}' 3.awk使用-v定義變數,但是awk中引用變數時直接使用變數名,不需要在變數前加$ 4.將awk中的結果賦值給變數傳遞給shell中用 方法一:可以使用eval()函式來將列印的結果轉換成變數。eval會將列印的值當做命令來進行處理,shell中定義變數的格式:變數名=變數值 例子:有個檔名為search.contract-0.0.5-SNAPSHOT.jar,按照-分割。將-前面的存為name變數,中間的版本號存為version變數。 eval $(ls |grep search.contract-0.0.5-SNAPSHOT.jar |awk -F"-" '{printf("name=%s;version=%s\n",$1,$2)}')[root@t-enter tmp]# eval $(ls |grep search.contract-0.0.5-SNAPSHOT.jar |awk -F"-" '{printf("name=%s;version=%s\n",$1,$2)}') [root@t-enter tmp]# echo $name search.contract [root@t-enter tmp]# echo $version 0.0.5方法二:如果只想儲存一個變數,可以通過變數名=$(操作print變數值)的方法來儲存 例如提取ifconfig eth0本機中的IP地址儲存到變數a中 a=$(ifconfig eth0 |awk -F":| *" '/inet addr/{print $4}')
[root@t-enter tmp]# a=$(ifconfig eth0 |awk -F":| *" '/inet addr/{print $4}') [root@t-enter tmp]# echo $a 192.168.174.55.只對包含某些內容的行進行操作 awk '/要匹配的內容/{進行的操作}' file,//內可以放入正則表示式,注意對一些特殊字元進行轉義,比如“[]\“ 6.awk不能直接修改原始檔,可以通過重導向輸出結果來修改原檔案。>(全部覆蓋檔案內容)或>>(追加到檔案) awk '/^root/{print $0 >"passwd"}' passwd 注意:重導向輸出的檔名要用雙引號括起來,否則會報錯 7.awk使用雙引號作為分隔符,可以使用單引號括起來,'"'