GAWK 指令 - 1
GNU AWK
gawk
係 GNU 版本嘅文本處理工具。
喺大部分 GNU/Linux 發行版入面,gawk
係預設嘅 awk
實現,所以喺日常使用中通常冇乜分別。
readlink -f /usr/bin/awk
/usr/bin/gawk
gawk
命令默認使用 ERE 模式。
基本語法
gawk [OPTIONS] program file
OPTIONS
:命令選項。program
:呢個命令入面仲有個程序。file
:處理嘅文件,如果省略,讀取 STDIN。
省略 file
係交互模式,輸入一行執行一次。
運行過程
- 讀入一行數據:
- 有匹配規則:
- 匹配成功:執行相關操作。
- 匹配失敗:唔執行操作。
- 無匹配規則:執行相關操作。
- 有匹配規則:
基礎用法
創建 foo 文件。
echo -e 'aa 11\nbb 22' > foo
對於每行數據,gawk
默認使用空格/制表符分隔欄位。
$N
:表示第 N 個欄位。$0
:表示整行數據。
gawk '{print $1}' foo
aa
bb
BEGIN/END 結構
- BEGIN:初始化,解釋之前執行。
- BODY:對每個記錄執行一次。
- END:結束處理。
留意使用引號 'EOF'
創建文件,咁樣就唔會處理特殊字符 $
。
cat <<'EOF' > foo.gawk
BEGIN {
FS=":"
print "User\tShell"
print "-------\t-------"
}
{
print $1 "\t" $6
}
END {
print "-------\t-------"
}
EOF
head -n 3 /etc/passwd | gawk -f foo.gawk
User Shell
------- -------
root /root
daemon /usr/sbin
bin /bin
------- -------
常用選項
指定分隔符
-F
選項可以修改行嘅分隔符。
gawk -F: '{print $1}' /etc/passwd | head -n 1
指定檔案
-f
選項可以指定檔案。
echo '{print $1 "-dir:" $6}' > foo.gawk
gawk -F: -f foo.gawk /etc/passwd | head -n 1
root-dir:/root
變量參數賦值
-v
選項可以喺 BEGIN 之前畀變量賦值。
gawk -v n=2 'BEGIN{print 2*n}'
4
如果唔需要喺 BEGIN 中使用,可以唔使用 -v
參數。
echo 'a b c' | gawk '{print $n}' n=2
b
內置變量
變量 $N
$N
仲可以賦值,字符串嘅雙引號唔可以省略。
echo 'hey man' | gawk '{$2="bro"; print $0}'
hey bro
變量 FS
Field Separator,字段分隔符。
gawk 'BEGIN{FS=":"} {print $1}' /etc/passwd | head -n 1
變量 NF
Number of Fields,表示記錄中嘅字段數量。
gawk -F: '$1=="root"{print $1":"$NF}' /etc/passwd
root:/bin/bash
變量 NR
Number of Records,表示而家處理緊嘅記錄編號,默認值係 1,處理完一行之後會加 1。
可以用嚟跳過文本嘅第一行,第一行嘅 NR
值係 1。
cat <<EOF > foo
name score
foo 90
bar 80
EOF
gawk '{if (NR>1) {if ($2>85) {print $1,$2}}}' foo
foo 90
變量 RS
記錄分隔符,輸入記錄分隔符,默認值係 \n
,表示以換行符分隔每條記錄。
將 RS
設置為 ""
表示以空行作為記錄分隔符,對於下面嘅文本,會分為上下 2 個記錄。
cat <<EOF > foo
apple
sweet
red
banana
sweet
yellow
EOF
設置 FS="\n"
,噉就可以透過 $N
獲取每行記錄。RS
同 FS
通常結合使用。
gawk 'BEGIN{RS=""; FS="\n"} {print $1"\t"$3}' foo
apple red
banana yellow
變量 OFS
Output Field Separator,輸出欄位分隔符。
echo 'aa,bb' | gawk 'BEGIN{FS=","; OFS="-"} {print $1,$2}'
aa-bb
變量 FIELDWIDTHS
指定字符寬度進行分隔。
echo 'abbc' | gawk 'BEGIN{FIELDWIDTHS="1 2 1"} {print $1,$2,$3}'
a bb c
條件同結構
條件表達式
==
、<
,<=
,>
,>=
。
gawk -F: '$7=="/bin/bash"{print $1}' /etc/passwd
輸出所有以 bash 啟動嘅用戶。
條件語句
if
裏面單條語句可以唔加 {}
。
echo -e '10\n20' | gawk '{if ($1>15) print $1}'
if
裡面多條語句要加 {}
。
echo -e '10\n20' | gawk '{if ($1>15) {x=2*$i; print x}}'
單行嘅 else
語句,前面嘅語句要加 ;
號。
echo -e '10\n20' | gawk '{if ($1>15) print $1; else print "no"}'
多行唔需要加分號。
echo -e '10\n20' | gawk '{
if ($i>15) {
x=2*$i
print x
} else {
print "no"
}
}'
FOR 語句
對每一行嘅字段求和,+=
同 ++
都支持。
echo '1 2 3' | gawk '{
total=0
for (i=1; i<=NF; i++) {
total += $i
}
print total
}'
WHILE 語句
對每一行嘅字段求和。
echo '1 2 3' | gawk '{
i=1
total=0
while (i<=NF) {
total += $i
i++
}
print total
}'
DO-WHILE 語句
對每一行嘅字段求和
echo '1 2 3' | gawk '{
i=1
total=0
do {
total += $i
i++
} while(i<=NF)
print total
}'
函數相關
內建函數
int(x)
:攞 x 嘅整數部分。exp(x)
:x 嘅指數。sqrt(x)
:x 嘅平方根。rand()
:比 0 大但小於 1 嘅隨機數。length(x)
:x 嘅字符串長度。tolower(x)
:將 x 轉做小寫。toupper(x)
:將 x 轉做大寫。
仲有好多,例如 gensub
,gsub
。
自定義函數
自定義函數必須出現喺 BEGIN
塊之前。
gawk '
function random(ts, num) {
srand(ts)
return int(num * rand())
}
BEGIN {
ts=systime()
print ts
print random(ts, 10)
}'
可以使用函數庫文件,再引用。
cat <<'EOF' > funclib.gawk
function random(ts, num) {
srand(ts)
return int(num * rand())
}
EOF
gawk 程序檔案如下。
cat <<'EOF' > test.gawk
BEGIN {
ts=systime()
print ts
print random(ts, 10)
}
EOF
使用 -f 選項引用兩個文件。
gawk -f funclib.gawk -f test.gawk
引用函數庫就唔可以用內聯程序模式,都需要引用。
其他例子
自定義變量
支持數學運算同浮點數,呢個唔比 bash 強 🤪。
gawk 'BEGIN{a=2; a=a*2/3; print a}'
1.33333
數組操作
特點:關聯數組,好似字典,無序。
gawk 'BEGIN{arr["name"]="foo"; print arr["name"]}'
可以用數字下標,其實都係字典。
gawk 'BEGIN{arr[3]="foo"; print arr[3]}'
遍歷陣列,刪除元素。
gawk 'BEGIN{
arr["a"]=1
arr[2]=2
arr["c"]="cat"
delete arr[2]
for (k in arr) {
print "key:",k," val:", arr[k]
}
}
'
key: a val: 1
key: c val: cat
格式化打印
處理浮點數。
gawk 'BEGIN{printf "%.2f\n", 2/3}'
0.67
指定闊度。
echo -e 'foo\nfoobar' | gawk '{printf "%8s\n", $1}'
左靠齊。
echo -e 'foo\nfoobar' | gawk '{printf "%-8s\n", $1}'