一、awk介紹
awk是Linux自帶的一個逐行掃描的文本處理工具,支持正則表達式、循環控制、條件判斷、格式化輸出。AWK自身帶有一些變量,可以在書寫腳本時調用。
二、基本語法格式
2.1、在shell中使用awk
awk [option] 代碼塊 文件名
- option的選項及含義
選項 | 含義 | 使用演示 | 演示說明 |
-F | 指定文件分隔符 | awk -F "\n" | 按\n做分隔符 |
-f | 使用文件中的內容作爲命令輸入 | awk -f script.txt | 使用script.txt文件中的內容作爲命令 |
-v | 給變量賦值,支持多個v賦值 | awk -v Num=$num -v Num1=$num1 | 把num的值給Num、num1的值給Num1 |
- 代碼塊的說明:
條件判斷'{要執行的內容}' 注:條件判斷與“{”之間不帶空格,{}的兩側要使用單引號"'’"包圍。
條件判斷爲真則執行{}中的內容,條件判斷爲假則不執行{}中的內容。
例如:
awk -F "," NR==2'{print $1}' awktest.txt
#將awktest.txt文件中的文本以",",如果行號爲2則打印第一列內容。
awk -F "," NR==10'{print "這是第"NR"行","第1列是:"$1,"第2列是:"$2}' awktest.txt
#打印多個列的字段、行號並於固定的字符串拼接
2.2、在腳本中使用awk代碼
有些腳本命令比較長,在shell中編輯比較麻煩,這時考慮將命令寫入腳本中方便保存和修改。
在腳本文件中,大致格式如下:
BEGIN{
語句一
語句二
}
表達式1 {要執行的內容}
表達式2 {要執行的內容}
END{
語句一
語句二
}
注意:{要執行的內容}中如果有多個語句要執行,使用","進行分割。在awk中,{}中的內容表示要執行的操作,賦值、判斷等操作可以放在{}之外。
- 創建一個文件awkScript.txt
vi awkScript.txt
以下腳本文件中的FS、NR是awk的自帶變量,後面的內容中對此進行解釋。
#awk的腳本文件
#開始部分,一般用於腳本執行前的初始化,比如設置每一列的標題、設置分割符等等。
BEGIN{
FS=","
print "第一列","第二列"
}
#這裏是主要執行的代碼塊
{print "這是第"NR"行"}
NR%2 {print NR,"這是偶數行"}
#END代碼塊。
END{
print "總計共有"NR"行"
print "腳本執行結束"
}
- awk以腳本的方式執行這些文件
awk -f awkScript.txt awktest.txt
三、awk的內置變量
awk內置一些變量,這些變量可能會隨着文本讀取的進度發生變化,比如現在讀取到第幾行。我們可以調用這些內置變量。
變量名稱 | 說明 | 使用示例 | 示例說明 |
$number | 記錄被分割後的第number列的字段,$表示整行文本。 | {print $1,$3} | 打印第1列和第3列字段 |
FS | 字段分割符(可使用FlieSplit記憶) | BEGIN{FS="\n"} | 使用換行分割文本 |
NF | 當前行中的字段數量 | {print "當前行共有"NF"列"} | 打印當前行的列數 |
NR | 當前的行號(NnumberRow,從1開始) | NR%2{print "這是偶數行"} | 判斷是否是偶數行 |
RS | 表示記錄分隔符,多行文本的情況下,RS字符將文本分割成幾個大塊(RowSplit) |
BEGIN{ FS="\N" RS=" " } |
對一個使用空行分割多個行的文本,RS表示的字符將文本分成多個段落,FS表示的字符將這些段落中的行分割成多個列。 |
OFS | 表示輸出字段之間分隔符,將輸出的多個字段使用OFS拼接,缺省爲" "。(OutFileSpilt) |
BEGIN{OFS=";"} {print "字段1","字段2","字段3"} |
輸出的字段1、字段2、字段3變成"字段1;字段2;字段3" |
ORS | 表示輸出行之間記錄分隔符,在兩個單獨行插入定義的字符串,缺省爲"\n" |
BEGIN{ ORS="\n\n" } |
輸出的文本行之間有兩個空行 |
四、awk的正則表達式
awk的正則表達式和其他語言的正則表達式規則一致
字符 |
描述 |
. |
可代替除一行之外的任何單個字符 |
* |
可代替零個或多個在它前面出現的字符 |
[chars] |
可代替chars中的任何一個字符,chars是一串字符序列。你可以用-符號來定義一個字符範圍。如果^是chars中的第一個字符,那麼將匹配沒有在chars中指定的字符 |
^ |
匹配一行的開頭 |
$ |
匹配一行的結尾 |
\ |
把\後面的字符照常輸出,通常用來轉義(不使用特殊含義)一個元字符 |
!~ | 匹配到的內容取反,表示不匹配 |
- 在{}包裹的語句塊之前使用正則表達式語法
awk ‘/REG/{action}’ /REG/爲要匹配的內容,{action}爲匹配成功後要執行的動作。
#打印awktest.txt文件中包含2020年時間的行(使用"\"對/符號進行轉義)
awk -F "," '/2020\/[0-9]{1,2}\/[0-9]{1,2}/{print $0}' awktest.txt
匹配到的結果爲:
在{}代碼塊中使用正則表達式語法
awk -F "," '{if($0 ~ "2020/07/01"){print $0}else{print "none"}}' awktest.txt
五、awk控制流語句
5.1、條件語句
awk的if語句類似於C語言的if語句
{
if ( $1 == "foo" ) {
if ( $2 == "foo" ) {
print "uno"
} else {
print "one"
}
} else if ($1 == "bar" ) {
print "two"
} else {
print "three"
}
}
5.2、循環語句
- do...while循環
{
count=1
do {
print "I get printed at least once no matter what"
} while ( count != 1 )
}
- for循環
for ( x = 1; x <= 4; x++ ) {
print "iteration",x
}
- break和continue語句
如同C語言一樣,awk提供了break、continue來控制awk的循環結構。break語句用於跳出最深層的循環,使循環立即終止,並繼續執行循環代碼塊後面的語句。continue語句使awk立即開始執行下一個循環迭代,而不執行代碼塊的其餘部分。
5.4、數組
在awk中,數組下標通常從1開始,而不是0:
myarray[1]="jim"
myarray[2]=456
awk不需要連續的下標編號,例如,給myarray[1]賦值之後可以直接賦值myarrary[10]。
awk可以使用"in"操作來遍歷數組中的所有元素,但這種遍歷是無序的,無法保證按下標順序輸出。
for ( x in myarray ) {
print myarray[x]
}
awk數組中還可以使用字符串下標,其實,不管你使用的下標是字符串還是數字,awk在幕後還將其認爲是字符串下標。
myarr["1"]="China"
print myarr["1"]
myarr["name"]="Mr. Whipple"
print myarr["name"]
六、awk的內置函數
awk並不像其他語言一樣,把字符串看作是字符數組。執行以下代碼:
mystring="How are you doing today?"
print mystring[3]
將會報錯:
awk: string.gawk:59: fatal: attempt to use scalar as array
爲了應對這種情況,awk內置了許多字符串函數。
字符串函數 | 功能說明 | 使用示例 | 示例說明 |
length() | 返回字符串的長度 | print length(mystring) | 打印mystring字符串的長度 |
index() | 返回子字符串在另一個字符串中出現的位置 | print index(mystring,"you") | 返回子字符串“you”在另一個mystring中出現的位置,如果沒有找到該字符串則返回0 |
tolower() | 返回字符串並且將所有字符轉換成小寫 | print tolower(mystring) | 把mystring所有的字母改成大寫 |
toupper() | 返回字符串並且將所有字符轉換成大寫 | print toupper(mystring) | 把mystring所有的字母改成小寫 |
substr() | 返回從字符串中選擇的子串 | awk '{print substr($0,2,10)}' | 打印字符串從第2位開始後面10個字符 |
match() | 返回子字符串在另一個字符串中出現的位置。它與index()的區別在於它並不搜索子串,它搜索的是正則表達式。,match()還將設置兩個變量,叫作RSTART和RLENGTH。RSTART包含返回值(第一個匹配的位置),默認返回RESTART,RLENGTH指定它佔據的字符跨度(如果沒有找到匹配,則返回-1) | print match($0,/2020\/07\/01/),RLENGTH | 打印2020/07/01匹配到的起始位置和它的長度。 |
sub() | 替換匹配的第一個字符序列,並返回整個字符串 | sub(regexp,replstring,mystring) | 用replstring替換在mystring中匹配regexp的第一個字符序列,sub()替換第一個regexp匹配 |
gsub() | 替換匹配的全部字符序列,並返回整個字符串 | gsub(regexp,replstring,mystring) | 用replstring替換全部在mystring中匹配regexp的第一個字符序列 |
split() | 分割字符串,並將各部分放到使用整數下標的數組中 | num=split($0,var,",") {print var[1]} | 將當前行的文本以","分割,放進var數組中,打印第一各元素。num爲接受分割後數組的長度。 |
七、awk的格式化輸出
然大多數情況下awk的print語句可以完成任務,但有時我們還需要更多。使用兩個函數printf()、sprintf(),將能讓輸出錦上添花。printf()會將格式化字符串打印到stdout,而sprintf()則返回可以賦值給變量的格式化字符串。
x=1
b="foo"
printf("%s got a %d on the last test\n","Jim",83)
myout=("%s-%d",b,x)
print myout