?? awk最新教程.txt
字號:
內部函數是 awk 提供的函數,可在 awk 程序的任何地方調用。5.1 數值方面的內部函數int(x) 求出 x 的整數部份,朝向 0 的方向做舍去。例如:int(3.9) 是 3,int(-3.9) 是 -3。sqrt(x) 求出 x 正的平方根值。例 sqrt(4)=2exp(x) 求出 x 的次方。例 exp(2) 即是求 e*e 。log(x) 求出 x 的自然對數。sin(x) 求出 x 的 sin 值。cos(x) 求出 x 的 cos 值。 atan2(y,x) 求 y/x 的 arctangent 值,所求出的值其單位是弧度量。rand() 得出一個隨機數值。此隨機數值平均分布在 0 和 1 之間。這個值不會是 0,也不會是 1。每次執行awk,rand 產生的數字都相同。 如:awk '{ for (i=1;i<10;i++) { x=rand() print x } }' 執行后,每打一次回車便產生10個0-1之間的隨機數。但第一次執行產生 的若干數字如100個和第二次執行產生的100個數字相同。srand(x) 設定產生隨機數的開始點為 x。如果在第二次你設定相同的 seed 值,你將再度得到相同序列的隨機數值。如果省略引數 x,例如 srand(),則現在的日期、時間會被當成初始值。這個方法可使得隨機數值是真正不可預測的。5. 2 字符串方面的內部函數index(in, find)它會在字符串 in 里面,尋找字符串 find第一次出現的地方,返回值是字符串 find出現在字符串 in里面的位置。如果在字符串 in里面找不到字符串find,則返回值為 0。例如:print index("peanut","an")會輸出 3。 length(string)求出 string字符串的長度。例如: length("abcde") 的返回值是 5。 match(string,regexp)match函數會在字符串 string 里面,尋找符合 regexp 的最長、最靠左邊的子字符串。返回值是 regexp 在 string 的開始位置,即 index值。 match 函數會設定內在變量 RSTART 等于 index,它也會設定內在變量 RLENGTH等于符合的字符個數。如果不符合,則會設定 RSTART 為0、RLENGTH 為 -1。如:awk '{ match("sfsdfgertertrtra","tert") print RSTART,RLENGTH }' 執行后,每次回車都會顯示9 4,意為第9位,長度為4 split(string,array,field_seperator)使用split返回字符串數組元素個數。工作方式如下:如果有一字符串,包含一指定分隔符 - ,例如AD2-KP9-JU2-LP-1,將之劃分成一個數組。使用 split,指定分隔符及數組名。此例中,命令格式為 split("AD2-KP9-JU2-LP-1",parts_array,"-"),split然后返回數組下標數,這里結果為4。sprintf(format,expression1,...) 與 printf 類似,但是 sprintf 并不輸出,而是返回字符串。例如: pi=sprintf(“%.2f (approx.)”,22/7) print pi 將會顯示 3.14 (approx.)sub(regexp,replacement,target)在字符串 target里面,尋找符合regexp的最長、最靠左邊的地方,以字符串 replacement代替最左邊的 regexp。例如: awk '{ str ="water, water, everywhere" sub(/at/, "ith",str) print str }' 結果字符串str會變成 "wither, water, everywhere"gsub(regexp,replacement,target)gsub與前面的 sub類似。在字符串 target 里面,尋找符合 regexp 的所有地方,以字符串 replacement 代替所有的 regexp。例如: str="water, water, everywhere" gsub(/at/, "ith",str) 結果字符串str會變成 wither, wither, everywhere substr(string, start, length)返回字符串 string 的子字符串,這個子字符串的長度為 length個字符,從第start個位置開始。例如:str=substr("washington",5,3) 返回值為"ing" 如果 length沒有出現,則返回的子字符串是從第 start個位置開始至結束。例如: awk 'BEGIN { oldstr="washington" } { newstr=substr(oldstr,5) print newstr }’執行后將顯示"ington" tolower(string) 將字符串string的大寫字母改為小寫字母。例如: awk 'BEGIN { oldstr="WASHINGTON" } { newstr= tolower(oldstr) print newstr }’ 執行后顯示: washingtontoupper(string) 將字符串string的小寫字母改為大寫字母。例如: toupper("MiXeD cAsE 123") 返回值為"MIXED CASE 123" 5.3 輸入輸出的內部函數close(filename)將輸入或輸出的文件filename關閉。例如:awk '{ print "new line">"new" }'前面的語句的作用是將”new line”這個字符串放入文件new中,注意語句中使用的是”>”符號,其作用將顯示內容轉向,在轉向的同時將文件中原有的內容清除掉,所以不論print語句執行幾遍,文件new中的內容都應該只有一行:”new line” 。但執行上例awk語句,敲5次回車后發現文件new中有5行new line,而不是一行。其原因是因為文件new被打開后,沒有被關閉,導致再次操作時發生錯誤。如果需要完成上例所設想的功能,應該使用下面的語句: awk '{ print "new line">"new" close(new) }' 另外,在一個awk中如使用追加符號“>>”可以不使用close語句,但為了避免多個awk語句可能存在對同一個文件的操作,在對文件操作完成后,最好都使用close關閉文件。system(command)此函數允許在awk中使用系統提供的Shell命令,命令執行完畢后將回到 awk程序。例如: awk '{ str=sprintf("head -%d filename",$1 ) system(str)}' 該語句將按輸入數字的值取出文件filename的前若干行。注意,在使用格式化語句的時候,首先要將格式化的字符串賦予某個變量,如例子中的str,然后再在system中使用。如果希望將命令執行的結果截獲下來,供awk中的語句使用,可以使用管道。如: awk ' { "cat filename|wc -l" | getline var #將文件filename的長度賦予變量var print var }' 管道線前面的語句可以不包括在system中。 getline函數的在這里的作用是將通過管道獲得的值存儲于var變量。 getline awk提供將輸入數據分解為記錄的功能,但對于某些任務來說,仍不能滿足數據處理的要求。比比如,在下列數據文件當中數據是以若干行為單位存放的: more data: begin zhangqiang 24 nan 96 wanggang 23 nan 97 zhaoyu 22 nu 98 end …… 如上所示,begin和end之間的數據是一個整體,在文件中的數據全部是以這種方式存放,當然在處理時也需要讀入一個單位后統一進行,在這種情況下,就可以用到getline函數。 getline函數用以讀取下一行的數據并進行字段分解操作,設置NF,NR和FNR。如果有一個記錄,getline返回1,如果遇到文件結束,返回 0,如果出現錯誤,返回-1。舉例: awk '/^begin/ { N=0 #在找到開始標志begin時,將變量N置0 while (getline && $0 !~ /^end/) #取下一行,并且下一行不是end時 { f[++N]=$0 } #將讀入的數據存入數組f中 for (i=1;i<=N;i++) #對begin與end之間的數據進行處理(已 { printf("%s " , f[i]) } #存入到數組f中。 print "" #換行 }' data getline函數還有其它用法: getline x #將下一個記錄讀入變量x中,不作分解,不設置NF getline < “filename” #從指定文件filename中讀取一行(存入$0中),而不是從當前文件中,對NR或FNR沒有影響,但對字段進行分解并且設置NF。再或者,如上頁例題中所示,通過管道截取命令執行后的結果。第六章 自定義函數(User-defined Functions) 復雜的 awk 程序常常要通過自定義函數來簡化。自定義的函數的使用與內部函數的使用方法一樣。 1) 函數定義的格式函數的定義可以放在 awk程序的任何地方。 一個自定義的函數其格式如下: function name (parameter-list) { body-of-function } name 是所定義的函數的名稱。一個正確的函數名稱可包括一序列的字母、數字、下標線 (underscores),但是不能用數字做開頭。 parameter-list是函數的參數列表(argument),各個參數之間以逗點隔開。 body-of-function包含 awk 的描述 (statement)。它是函數定義里最重要的部份,它決定函數實際要做何種事。 2)函數定義的例子下面這個例子,會將每個記錄的第一個字段值的平方與第二個字段之值的平方加起來。 awk ‘{ print $1,$2,"sum =",SquareSum($1,$2) } function SquareSum(x,y) { sum=x*x+y*y return sum }’ filename 在定義了函數SquareSum之后,對每一行數據的處理只需經過一次調用就可以。但定義自定義函數最大的好處還是可以在不同的地方調用,而不必每次都寫上一堆,此外還使程序結構清楚,易讀,易維護。第七章 示例 awk '{ if (NF > max) max = NF } END { print max }' filename 此程序會輸出所有輸入行中,包含字段最多的行的字段數。 awk 'length($0) > 80' filename 此程序會輸出一行超過 80 個字符的每一行。此處只有 pattern 被列出,action 是采用缺省的 print。 awk 'NF > 0' filename 對于擁有至少一個字段的所有行,此程序皆會輸出。這是一個簡單的方法,將一個文件里的所有空白行刪除。 awk '{if (NF > 0) print}' filename 對于擁有至少一個字段的所有行,此程序皆會輸出。這是一個簡單的方法,將一個文件里的所有空白行刪除。 awk 'BEGIN { for (i = 1; i <= 7; i++) print int(101 * rand()) }' filename 此程序會輸出 0 到 100 之間的 7 個亂數值。 ls -l files| awk 'BEGIN { x=0 } { x += $4 } END { print "total bytes: " x }' filename 此程序會輸出所有指定的文件之bytes數目的總和。 expand file | awk '{if (x < length()) x = length()} END {print "maximum line length is " x}' filename 此程序會將指定文件里最長一行的長度輸出。expand 會將 tab 改成 space,所以是用實際的右邊界來做長度的比較。 awk 'BEGIN {FS = ":"} {print $1 | "sort"}' /etc/passwd 此程序會將所有用戶的login名稱,依照字母的順序輸出。 awk '{nlines++} END {print nlines}' filename 此程序會將一個文件的總行數輸出。 awk 'END {print NR}' filename 此程序也會將一個文件的總行數輸出,但是計算行數的工作由awk來做。 awk '{print NR,$0}' filename 在輸出文件的內容時,會在每行的最前面輸出行號,它的功能與 'cat -n' 類似。 □ 附錄 例程分析 1. 關機帳號大家都知道在UNIX系統中,關機命令都必須在超級用戶執行(其它用戶沒有關機權限),而在有些情況,我們并不希望直接使用UNIX系統的人知道根用戶的口令(如網點端的操作員),而又想讓他可以直接正常關閉機器, 并且在關機時,系統中的其它注冊用戶最好都退到login:狀態. 下面是一個運行在UNIX系統上的關機程序,主要是針對操作員設計的,使用它可以在不知道超級用戶口令的情況下,通過系統提供的關機命令正常關閉計算機, 并且它在關機之前檢測其它用戶是否都已退出,避免系統數據不必要的損失。 一般情況下,在UNIX系統中建立一個關機帳號有以下兩個步驟: 1. 在系統中建立一個普通用戶,如halts,其用戶主為halts,用戶組為group.將關機權限賦予該用戶. 2. 在該用戶目錄下編輯一個關機程序,即下例所示(程序名為halts),賦予其可執行權限.在該用戶的.profile文件的第一行增加trap 'clear;exit' 0 1 2 3 5 15,在最后一行增加一行exec halts #halts: 關機帳號程序,用以關閉計算機 1999/3/21 trap 'clear;exit' 0 1 2 3 5 15 #截獲中斷信號,當后面所列信號出現時執行單 #引號中的命令,即先清屏然后退出 #===============================================================================# testscreen() #函數,用于測試哪些屏幕還沒有退出 { #函數體開始符號 she=`tty` #變量she被賦予當前所在屏幕的設備名 if [ "$she" != "/dev/tty01" ] #如果變量she的值不等于第一個屏幕的設備名 then #則 echo "\n\t\t請在第一屏關機 !\c" #顯示“請在第一屏關機 !”字樣 sleep 2 #等待2秒鐘后 exit 0 #退出程序 fi #if語句結束 } #函數體結束符號 #===============================================================================# yesyn() #函數,用于測試用戶的輸入是‘y’還是‘n’ { #函數體開始符號 while echo "\n$* (y/n) \c">&2 #當正常顯示提示信息($*)后進入循環 do #作以下操作 read yn rest #讀用戶輸入并將輸入放入yn變量中 case $yn in #當變量yn的值為 [Yy]) echo ; return 0 ;; #大寫字母Y或小寫字母y時,函數返回0 [Nn]) echo ; return 1 ;; #大寫字母N或小寫字母n時,函數返回1 *) echo "\n\t\t稍后請回答 y 或 n !\c">&2 #其它輸入時,顯示“稍后請回答 y 或 n !” sleep 1 #等待1秒鐘 clear ;; #清屏 esac #case語句結束 done #while語句結束 } #函數體結束符號 #===============================================================================# menu() #函數,用于顯示如下菜單 { #函數體開始符號 echo #換行 echo "\t\t ┏━━━━━━━━━━━━┓" #顯示菜單框 echo "\t\t ┃ 1) 強行 關 機 ┃" #顯示選項 echo "\t\t ┃ 2) 重 新 測 試 ┃" #顯示選項 echo "\t\t ┃ 3) 退 出 ┃" #顯示選項 echo "\t\t ┗━━━━━━━━━━━━┛" #顯示菜單框 echo "\n\t\t 請輸入選擇: \c" #顯示“請輸入選擇” } #函數體結束符號 #===============================================================================# exam() #函數,用于檢測有哪些屏幕還沒有退出 { #函數體開始符號 clear #清屏 status=0 #狀態變量stutes被賦初值0(表示全部退出) sum=`who|wc -l` #變量sum被賦于尚未退出的用戶數 if [ $sum -ne 1 ] #如果該數目不等于1 then #那么 status=1 #狀態變量stutes被賦初值1(表示有用戶尚未退出) echo "^G^G" #響鈴,注意^G是一個組合鍵Ctrl-g echo "\n\n" #換行 for i in `who|awk ' $2!="tty01" { which=substr($2,4,2) print which }'` #該語句首先將who命令的輸出傳遞給awk語句,awk語句檢測輸入的 #每一行的第二個字段,當這個字段的值不是"tty01"時,取出該字段 #的第三四位,并將其依此賦予變量which,然后將變量which的值輸出 #當以上語句有輸出時,將輸出依次賦于變量i,進入for循環語句 do echo "\t\t\t第 $i 屏尚未退出 !" #顯示“第 n 屏尚未退出 !”,n的值取自變量i done echo "\n\t\t\t請退出上述屏幕后再進行關機 !" #顯示字符串 echo "\n\t\t\t按回車鍵繼續 \c" #顯示字符串 read key #讀用戶輸入,并將其放入變量key中。其作用是 #等回車鍵被按下后,和序繼續執行。 fi return $status #將變量status的值作為函數的返回值 } #===============================================================================# downs() #函數,用于關閉計算機 { echo "請等待......" #顯示"請等待......" 字樣 /tcb/bin/asroot shutdown -g0 -y #執行關機命令 exit 0 #退出程序 (此句亦可省略) } #===============================================================================# main() #主函數,控制整個程序的流程 { clear #清屏 testscreen #檢測是否在第一屏 echo "^G\c" #響鈴 yesyn "\n\n\t\t本程序用于關閉計算機 是否要關閉(Y/N): \c" #顯示"是否關機(Y/N)"的提示,接收用戶輸入 if [ $? -eq 1 ] #當函數yesyn的返回值為1時 then #就 clear #先清屏 exit 0 #然后退出程序 fi while true #無條件進入while循環語句 do exam #檢測是否還有用戶沒有退出 if [ $? -eq 0 ] #當函數exam的返回值為0時 then #那么 downs #執行關機函數 else #否則 menu #執行菜單顯示函數 read key #讀用戶輸入,并將其放入變量key中 case $key in #當變量key的值為 1) downs ;; #1時,執行關機函數downs 3) exit 0 ;; #3時,退出程序 *) echo "請回答y或n">&2;; #其它輸入時, 先顯示"請回答y或n"后無條件進入下次循環 esac #case語句結束 fi #if語句結束 done #while語句結束 } #===============================================================================# main #執行主函數 2. 臨測程序 下面是一個網絡連通檢測程序,它可以在屏幕上直觀地反映出網絡中各目標網點的連通狀況。程序循環檢測,直到被中斷為止。從簡單易讀的角度出發,該段程序對屏幕顯示的格式只作了簡單處理,在網點數較多的情況下,需要稍作修改。 #本程序用以檢測客戶端連通情況 1999/3/21 #============================================================================# tests() #函數,用以檢測一個網點端的連通狀況,連通返回0,否則返回1。 #網點名由位置參數確定 { num=`ping -c 1 $1|awk '$2=="packets" { data=substr($7,1,1) print data }'` #上面一句是將“ping -c 1 $1”命令的輸出轉向給awk語句,awk將第二個 #字段為“packets”的那一行的第七個字段的第一個字符賦予變量num。此數 #是“ping -c 1 $1”命令返回的丟包率,0為通,非0為不通 if [ $num -eq 0 ] #如果變量num的值為何0 then #則 return 0 #返回0值 else #否則 return 1 #返回1 fi #if語句結束 } #============================================================================# all() #函數,用以檢測所有網點端的網絡連通性 { hang=3 #設置行變量的初始值為3 lie=10 #設置列變量的初始值為10 for i in lan0 serial0 zongying yiying erying sanying siying wuying liuying #當i變量為“lan0 serial0 ......wuying liuying”等網點端機器名時 do #作如下工作 tput cup $hang $lie #將光標定位在初始位置 echo "\t\t^[[36m →^[[37m${i}: \c" #顯示當前網點機器名 tests $i #用tests函數測試該網點是否為通 tput cup $hang $lie #光標定位于$hang $lie if [ $? -eq 0 ] #如果tests函數的返回值等于0 then #則 echo "\t\t ^[[33m→^[[37m ${i}\t ^[[32m ● ^[[37m\c" #顯示綠色● sleep 1 #等待1秒鐘 else #否則 echo "\t\t ^[[33m→^[[37m ${i}\t ^[[31m ● ^[[37m\c" #顯示紅色● fi hang=`expr $hang + 2` #行變量加二 sleep 1 done tput cup 22 10 #光標定位于 22 10 echo " 呼市育財信用社線路連通狀況表 ^[[32m●^[[37m: 通 ^[[31m●^[[37m: 不通" #顯示 ” 呼市育財信用社線路連通狀況表 ●(綠色): 通 ●(紅色): 不通” } #============================================================================# main() #主函數 { clear #清屏 tput cup 22 10 #光標定位于 22 10 echo " 呼市育財信用社線路連通狀況表 ^[[32m●^[[37m: 通 ^[[31m●^[[37m: 不通" while true #無條件進入while循環 do all #調用all函數 done } #============================================================================# TERM=ansi #給終端類型變量賦值ansi export TERM #聲明TERM變量 main #執行主函數 3. 數據查詢程序相信大家都有同感,在需要查尋所有儲種戶數和金額的時候,在菜單中或數據庫中一項一項地查找是一件很繁瑣的事情,特別是在初始建帳,需要核對錄入數據正確性的時候。下面一段程序就是為自動查詢數據設計的。當然它十分簡單,比如它沒有檢測輸入所號的否合法性等,但比較易讀和實用。 #本程序用于查詢Informix數據庫中某個儲蓄所活期、定期、零整儲種的記錄數 #及總金額,查詢結果顯示在屏幕上 #==========================================================================# zzbsum() #過程,用于獲得某所定期儲種的記錄數及總金額 { echo "\c" #換行 dbaccess bankstar</dev/null 2>/tmp/error unload to /tmp/jieguo0 select sum(jce) from zzb where zh[1,7]="$1"; unload to /tmp/jieguo1 select count(*) from zzb where zh[1,7]="$1"; END #以上語句以Here文本的方式,調用dbaccess工具中的SQL語句將某所 #定期儲種的總金額及記錄數分別下載到/tmp/jieguo0,/tmp/jieguo1文件中 #其中,儲蓄所號是由該過程的位置參數(即$1)確定的 sum0=`awk -F '|' '{ print $1 }' /tmp/jieguo0` sum1=`awk -F '|' '{ print $1 }' /tmp/jieguo1` #以上兩句分別取出/tmp/jieguo0,/tmp/jieguo1文件中的第一個字段,并 #將其分別賦予變量sum0及sum1 echo "\t整整簿總結存額: $sum0 \c" echo "\t整整簿總戶數: $sum1" #以上兩句將字符串及變量的值分別顯示到屏幕上 } #==========================================================================# zzb() #過程,用于獲得某所定期儲種某一檔次(存期)的記錄數及總金額 { #過程中的語句用法同hzbsum(),存期由該過程的位置參數(即$2)確定 echo "\c" dbaccess bankstar</dev/null 2>/tmp/error unload to /tmp/jieguo0 select sum(jce) from zzb where zh[1,7]="$1" and qx="$2"; unload to /tmp/jieguo1 select count(*) from zzb where zh[1,7]="$1" and qx="$2"; END sum0=`awk -F '|' '{ print $1 }' /tmp/jieguo0` sum1=`awk -F '|' '{ print $1 }' /tmp/jieguo1` echo "\t整整簿${2}總結存: $sum0 \c" echo "\t整整簿${2}總戶數: $sum1" } #==========================================================================# #依照上面的形式很容易寫出活期、零整的過程:hzbsum()、lzbsum()、lzb() main() #主過程,詢問儲蓄所號及調用子過程 { clear #清屏 echo "\n\n\t\t請輸入儲蓄所號 : \c" #顯示提示字符串 read cxsh #讀取輸入 echo #換行 hzbsum $cxsh #調用過程hzbsum,變量cxsh的值為位置參數 echo #換行 zzbsum $cxsh #調用過程zzbsum,變量cxsh的值為位置參數 for i in 03 12 24 36 60 96 do zzb $cxsh $I done #以for語句循環調用過程zzb,第二個位置參數 #分別為 03 12 24 36 60 96 echo #換行 lzbsum $cxsh #調用過程lzbsum,變量cxsh的值為位置參數 lzb $cxsh 12 #調用過程lzb,“03”作為第二個位置參數,以下用法相同 lzb $cxsh 36 lzb $cxsh 60 rm /tmp/jieguo0 /tmp/jieguo1>/dev/null 2>/dev/null #刪除臨時文件 } #===========================================================================# main #調用main主過程
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -