Awk Cheat Sheet

每行后面增加一行空行

awk '1;{print ""}'   
awk 'BEGIN{ORS="\n\n"};1' 
1
2

每行后面增加一行空行。输出文件不会包含连续的两个或两个以上的空行
注意:在Unix系统, DOS行包括的 CRLF (\r\n) 通常会被作为非空行对待
因此 'NF' 将会返回TRUE。

awk 'NF{print $0 "\n"}'   
1

每行后面增加两行空行

awk '1;{print "\n"}
1

编号和计算:

以文件为单位,在每句行前加上编号 (左对齐)

使用制表符 (\t) 来代替空格可以有效保护页变的空白。

awk '{print FNR "\t" $0}' files*   
1

用制表符 (\t) 给所有文件加上连贯的编号。

awk '{print NR "\t" $0}' files*

##3 以文件为单位,在每句行前加上编号 (编号在左,右对齐)
如果在DOS环境下,需要写两个'%'

awk '{printf("%5d : %s\n", NR,$0)}'   
1

给非空白行的行加上编号

记得Unix对于 \r 的处理的特殊之处。(上面已经提到)

awk 'NF{$0=++a " :" $0};{print}'   
awk '{print (NF? ++a " :" :"") $0}'   
1
2

计算行数 (模拟 "wc -l")

awk 'END{print NR}'   
1

计算每行每个区域之和

awk '{s=0; for (i=1; i<=NF; i++) s=s+$i; print s}'   
1

计算所有行所有区域的总和

awk '{for (i=1; i<=NF; i++) s=s+$i}; END{print s}'   
1

打印每行每区域的绝对值

awk '{for (i=1; i<=NF; i++) if ($i < 0) $i = -$i; print }'   
awk '{for (i=1; i<=NF; i++) $i = ($i < 0) ? -$i : $i; print }'   
1
2

计算所有行所有区域(词)的个数

awk '{ total = total + NF }; END {print total}' file  
1

打印包含 "Beth" 的行数

awk '/Beth/{n++}; END {print n+0}' file  
1

打印第一列最大的行 并且在行前打印出这个最大的数

awk '$1 > max {max=$1; maxline=$0}; END{ print max, maxline}'   
1

打印每行的列数,并在后面跟上此行内容

awk '{ print NF ":" $0 } '   
1

打印每行的最后一列

awk '{ print $NF }'   
1

打印最后一行的最后一列

awk '{ field = $NF }; END{ print field }'   
1

打印列数超过4的行

awk 'NF > 4'   
1

打印最后一列大于4的行

awk '$NF > 4'   
1

##构建字符串:

构建一指定长度的字符串(比如,513个空格)

awk 'BEGIN{while (a++<513) s=s " "; print s}'   
1

在某一位置中插入以特定长度的字符串

例子:在每行第6列后插入49个空格

gawk --re-interval 'BEGIN{while(a++<49)s=s " "};{sub(/^.{6}/,"&" s)};1'   
1

构建数组:

以下两个部分并不是一句话脚本,但是这些技巧相当便捷所以也包括进来

构建一个叫"month"的数组,以数字为索引,month[1]就是'Jan',month[2]就是 'Feb',month[3]就是'Mar',以此类推。

split("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec", month, " ")   
1

构建一个叫"mdigit"的数组,以字符串为索引,mdigit["Jan"] 等于 1,

mdigit["Feb"] 等于 2,等等。需要有"month"数组。

for (i=1; i<=12; i++) m_digit[month[i]] = i

文本转换和替代:

在Unix环境:转换DOS新行 (CR/LF) 为Unix格式

awk '{sub(/\r$/,"")};1' # 假设每行都以Ctrl-M结尾

在Unix环境:转换Unix新行 (LF) 为DOS格式

awk '{sub(/$/,"\r")};1'

在DOS环境:转换Unix新行 (LF) 为DOS格式

awk 1

在DOS环境:转换DOS新行 (CR/LF) 为Unix格式 DOS版本的awk不能运行, 只能用gawk:

gawk -v BINMODE="w" '1' infile >outfile

###用 "tr" 替代的方法。
tr -d \r <infile >outfile # GNU tr 版本为 1.22 或者更高

删除每行前的空白(包括空格符和制表符)

使所有文本左对齐

awk '{sub(/^[ \t]+/, "")};1'

删除每行结尾的空白(包括空格符和制表符)

awk '{sub(/[ \t]+$/, "")};1'

删除每行开头和结尾的所有空白(包括空格符和制表符)

awk '{gsub(/^[ \t]+|[ \t]+$/,"")};1'
awk '{$1=$1};1' # 每列之间的空白也被删除

在每一行开头处插入5个空格 (做整页的左位移)

awk '{sub(/^/, " ")};1'

用79个字符为宽度,将全部文本右对齐

awk '{printf "%79s\n", $0}' file*

用79个字符为宽度,将全部文本居中对齐

awk '{l=length();s=int((79-l)/2); printf "%"(s+l)"s\n",$0}' file*

每行用 "bar" 查找替换 "foo"

awk '{sub(/foo/,"bar")}; 1' # 仅仅替换第一个找到的"foo"
gawk '{$0=gensub(/foo/,"bar",4)}; 1' # 仅仅替换第四个找到的"foo"
awk '{gsub(/foo/,"bar")}; 1' # 全部替换

在包含 "baz" 的行里,将 "foo" 替换为 "bar"

awk '/baz/{gsub(/foo/, "bar")}; 1'

在不包含 "baz" 的行里,将 "foo" 替换为 "bar"

awk '!/baz/{gsub(/foo/, "bar")}; 1'

将 "scarlet" 或者 "ruby" 或者 "puce" 替换为 "red"

awk '{gsub(/scarlet|ruby|puce/, "red")}; 1'

倒排文本 (模拟 "tac")

awk '{a[i++]=$0} END {for (j=i-1; j>=0;) print a[j--] }' file*

如果一行结尾为反斜线符,将下一行接到这行后面

(如果有连续多行后面带反斜线符,将会失败)

awk '/\/ {sub(/\\/,""); getline t; print $0 t; next}; 1' file*

排序并打印所有登录用户的姓名

awk -F ":" '{ print $1 | "sort" }' /etc/passwd

以相反的顺序打印出每行的前两列

awk '{print $2, $1}' file

调换前两列的位置

awk '{temp = $1; $1 = $2; $2 = temp}' file

打印每行,并删除第二列

awk '{ $2 = ""; print }'

倒置每行并打印

awk '{for (i=NF; i>0; i--) printf("%s ",i);printf ("\n")}' file

用逗号链接每5行

awk 'ORS=NR%5?",":"\n"' file

择性的打印某些行:

打印文件的前十行 (模拟 "head")

awk 'NR < 11'

打印文件的第一行 (模拟 "head -1")

awk 'NR>1{exit};1'

打印文件的最后两行 (模拟 "tail -2")

awk '{y=x "\n" $0; x=$0};END{print y}'

打印文件的最后一行 (模拟 "tail -1")

awk 'END{print}'

###打印匹配正则表达式的行 (模拟 "grep")
awk '/regex/'

打印不匹配正则表达式的行 (模拟 "grep -v")

awk '!/regex/'

打印第5列等于"abc123"的行

awk '$5 == "abc123"'

打印第5列不等于"abc123"的行

这个同样可以用于打印少于5列的行

awk '$5 != "abc123"'
awk '!($5 == "abc123")'

用正则匹配某一列

awk '$7 ~ /^[a-f]/' # 打印第7列匹配的行
awk '$7 !~ /^[a-f]/' # 打印第7列不匹配的行

打印匹配正则表达式的前一行,但是不打印当前行

awk '/regex/{print x};{x=$0}'
awk '/regex/{print (x=="" ? "match on line 1" : x)};{x=$0}'

打印匹配正则表达式的后一行,但是不打印当前行

awk '/regex/{getline;print}'

以任何顺序查找包含 AAA、BBB 和 CCC 的行

awk '/AAA/; /BBB/; /CCC/'

以指定顺序查找包含 AAA、BBB 和 CCC 的行

awk '/AAA.*BBB.*CCC/'

打印长度大于64个字节的行

awk 'length > 64'

打印长度小于64个字节的行

awk 'length < 64'

打印从匹配正则起到文件末尾的内容

awk '/regex/,0'
awk '/regex/,EOF'

打印指定行之间的内容 (8-12行, 包括第8和第12行)

awk 'NR==8,NR==12'

打印第52行

awk 'NR==52'
awk 'NR==52 {print;exit}' # 对于大文件更有效率

打印两个正则匹配间的内容 (包括正则的内容)

awk '/Iowa/,/Montana/' # 大小写敏感

选择性的删除某些行:

删除所有空白行 (类似于 "grep '.' ")

awk NF
awk '/./'

删除重复连续的行 (模拟 "uniq")

awk 'a !~ $0; {a=$0}'

删除重复的、非连续的行

awk '! a[$0]++' # 最简练
awk '!($0 in a) {a[$0];print}' # 最有效

提取日志中的手机号并且统计

awk -F "&" '/userCode=/{print substr($4,10,21)}' localhost_access_log.2020-06-*.txt |sort | uniq -c > mobile.txt

Command Reference

Basics I

args description
$1 Reference first column
awk '/pattern/ {action}' file Execute action for matched pattern 'pattern' on file 'file'
; Char to separate two actions
print Print current record line
$0 Reference current record line

Variables I

args description
$2 Reference second column
FS Field separator of input file (default whitespace)
NF Number of fields in current record
NR Line number of the current record

Basics II

args description
^ Match beginning of field
~ Match opterator
!~ Do not match operator
-F Command line option to specify input field delimiter
BEGIN Denotes block executed once at start
END Denotes block executed once at end
str1 str2 Concat str1 and str2

One-Line Exercises I

args description
awk '{print $1}' file Print first field for each record in file
awk '/regex/' file Print only lines that match regex in file
awk '!/regex/' file Print only lines that do not match regex in file
awk '$2 == "foo"' file Print any line where field 2 is equal to "foo" in file
awk '$2 != "foo"' file Print lines where field 2 is NOT equal to "foo" in file
awk '$1 ~ /regex/' file Print line if field 1 matches regex in file
awk '$1 !~ /regex/' file Print line if field 1 does NOT match regex in file

Variables II

args description
FILENAME Reference current input file
FNR Reference number of the current record relative to current input file
OFS Field separator of the outputted data (default whitespace)
ORS Record separator of the outputted data (default newline)
RS Record separator of input file (default newline)

Variables III

args description
CONVFMT Conversion format used when converting numbers (default %.6g)
SUBSEP Separates multiple subscripts (default 034)
OFMT Output format for numbers (default %.6g)
ARGC Argument count, assignable
ARGV Argument array, assignable
ENVIRON Array of environment variables

Functions I

args description
index(s,t) Position in string s where string t occurs, 0 if not found
length(s) Length of string s (or $0 if no arg)
rand Random number between 0 and 1
substr(s,index,len) Return len-char substring of s that begins at index (counted from 1)
srand Set seed for rand and return previous seed
int(x) Truncate x to integer value

Functions II

args description
split(s,a,fs) Split string s into array a split by fs, returning length of a
match(s,r) Position in string s where regex r occurs, or 0 if not found
sub(r,t,s) Substitute t for first occurrence of regex r in string s (or $0 if s not given)
gsub(r,t,s) Substitute t for all occurrences of regex r in string s

Functions III

args description
awk 'NR!=1{print $1}' file Print first field for each record in file excluding the first record
awk 'END{print NR}' file Count lines in file
awk '/foo/{n++}; END {print n+0}' file Print total number of lines that contain foo
awk '{total=total+NF};END{print total}' file Print total number of fields in all lines
awk '/regex/{getline;print}' file Print line immediately after regex, but not line containing regex in file
awk 'length > 32' file Print lines with more than 32 characters in file
awk 'NR==12' file Print line number 12 of file