7.Shell脚本修炼手册---awk基础入门版
awk 使用手册 - 常用版
文章目录
- awk 使用手册 - 常用版
- awk 介绍
- awk 命令
- awk 命令格式
- awk 工作流
- awk 使用示例
- awk 命令选项
- --help 选项
- -F 选项:指定字段分隔符
- -v 选项:预先定义变量
- -p 选项:导出格式化的脚本代码
- awk 内置变量 (常用)
- 实例:内置变量的使用
- awk 运算符 (常用)
- 示例:运算符的使用
- awk 输出重定向
- 覆盖重定向 `>`
- 追加重定向 `>>`
- 管道 `|`
- 双向管道 `|&`
awk 介绍
awk 是一个强大的文本分析工具,更像是一门轻量级编程语言。它支持自定义变量、条件语句、循环、数组、正则表达式和函数等功能,能灵活处理各种文本任务。
简单来说,awk 的工作逻辑是按行读取数据,根据设定的条件筛选行,再对筛选出的行执行操作。日常常用它来做这些事:
- 处理文本(比如提取特定内容、替换字符)
- 生成格式化的报告(比如统计结果按固定格式输出)
- 执行简单的算术运算(比如求和、计数)
- 处理字符串(比如计算长度、匹配子串)
awk 命令
awk 命令格式
awk [选项] '脚本' 文件名... # 直接在命令行写处理逻辑(脚本)
awk [选项] -f 脚本文件 文件名... # 从文件中读取处理逻辑(脚本)
脚本
:定义对数据的处理规则(比如筛选条件、输出内容)。文件名
:awk 要处理的文件;也可以接收其他命令的输出作为输入(通过管道|
)。-f 脚本文件
:如果处理逻辑复杂,可把脚本写在文件里,用-f
指定文件路径。
awk 工作流
awk 处理数据的过程可以分为 3 步,按顺序执行:
- 执行
BEGIN {命令}
块
在读取任何输入数据之前执行,通常用来初始化变量、打印表头(比如统计报告的标题行)。 - 逐行处理
模式 {命令}
块
从输入中一行一行读数据,每读一行就检查是否符合 “模式”(比如包含某个关键词),符合就执行后面的 “命令”。
如果省略 “模式”,默认对每一行执行 “命令”;如果 “命令” 是print
,会默认打印整行。 - 执行
END {命令}
块
读完所有数据后执行,通常用来输出最终结果(比如统计的总和、计数)。
awk 使用示例
先准备一个示例文件employee.txt
,包含员工编号、姓名、部门和年龄:
# 创建示例文件,内容如下
[bq@shell ~]$ cat << 'EOF' > employee.txt
1) 张三 技术部 23
2) 李四 人力部 22
3) 王五 行政部 23
4) 赵六 技术部 24
5) 朱七 客服部 23
EOF
示例 1:打印所有雇员信息
# { print } 表示打印当前行(默认行为),等价于{ print $0 }($0代表整行)
[bq@shell ~]$ awk '{ print }' employee.txt
1) 张三 技术部 23
2) 李四 人力部 22
3) 王五 行政部 23
4) 赵六 技术部 24
5) 朱七 客服部 23
示例 2:通过脚本文件打印雇员信息
如果处理逻辑较长,可把脚本写在文件中:
# 创建脚本文件commands.awk,内容为打印每一行
[bq@shell ~]$ cat commands.awk
{ print }# 用-f指定脚本文件,效果和示例1相同
[bq@shell ~]$ awk -f commands.awk employee.txt
1) 张三 技术部 23
2) 李四 人力部 22
3) 王五 行政部 23
4) 赵六 技术部 24
5) 朱七 客服部 23
示例 3:输出包含 “张三” 的行
# 模式为/张三/,表示匹配包含“张三”的行,匹配后执行{ print }(可省略)
[bq@shell ~]$ awk '/张三/ { print }' employee.txt
1) 张三 技术部 23# 省略{ print },默认打印匹配的行
[bq@shell ~]$ awk '/张三/' employee.txt
1) 张三 技术部 23
示例 4:统计部门包含 “术” 的员工数量
实验流程:
- 定义匹配规则:筛选部门名称包含 “术” 的行(比如 “技术部”);
- 对匹配的行计数:每匹配一行,计数器
count
加 1; - 所有行处理完后,在
END
块中打印计数结果。
[bq@shell ~]$ awk '
/术/ { count=count+1 } # 匹配含“术”的行,count累加1(awk变量默认初始化为0)
END { print "Count="count } # 所有行处理完后,打印总数
' employee.txt
运行结果:
Count=2 # 技术部有张三、赵六,共2人
示例 5:输出行总长度大于 10 的行
awk 的length(变量)
函数可计算字符串长度,length($0)
表示整行的长度:
# 模式为length($0)>10,即行长度大于10的行才打印
[bq@shell ~]$ awk 'length($0)>10 { print $0 }' employee.txt
所有行的长度都大于 18,因此输出所有行:
1) 张三 技术部 23
2) 李四 人力部 22
3) 王五 行政部 23
4) 赵六 技术部 24
5) 朱七 客服部 23
awk 命令选项
–help 选项
查看 awk 的帮助信息,包含所有选项和用法示例:
[bq@shell ~]$ awk --help
-F 选项:指定字段分隔符
默认用空格分隔一行中的字段(比如 “张三 技术部” 中,“张三” 是第 2 个字段,“技术部” 是第 3 个)。-F
可自定义分隔符(比如冒号、逗号)。
示例:提取/etc/passwd
中的用户名和家目录
/etc/passwd
的内容格式为 “用户名:密码:UID:GID: 描述:家目录:shell”,用冒号分隔:
# 先查看第一行内容
[bq@shell ~]$ head -n1 /etc/passwd
root:x:0:0:root:/root:/bin/bash# 用-F:指定分隔符为冒号,打印第1个字段(用户名)和第6个字段(家目录)
[bq@shell ~]$ head -n1 /etc/passwd | awk -F : '{ print $1" "$6 }'
root /root # 输出:用户名 家目录
-v 选项:预先定义变量
在 awk 处理数据前定义变量,可用于传递外部值(比如 Shell 变量)到 awk 中。
示例 1:传递 Shell 变量到 awk
# 在Shell中定义变量VAR=10000
[bq@shell ~]$ VAR=10000# 用-v VARIABLE=$VAR把VAR的值传给awk的VARIABLE变量,然后打印
[bq@shell ~]$ echo | awk -v VARIABLE=$VAR '{ print VARIABLE }'
10000 # 输出传递的变量值
示例 2:直接在命令行定义变量
也可以在文件名前直接写 “变量 = 值”,传给 awk:
# Shell中定义var1和var2
[bq@shell ~]$ var1="aaa"
[bq@shell ~]$ var2="bbb"# 用v1=$var1 v2=$var2定义awk变量,打印这两个变量
[bq@shell ~]$ echo | awk '{ print v1,v2 }' v1=$var1 v2=$var2
aaa bbb # 输出变量值# 处理文件时同样有效
[bq@shell ~]$ awk '{ print v1,v2 }' v1=$var1 v2=$var2 /etc/hostname
aaa bbb # 输出变量值(同时会打印/etc/hostname的内容,此处省略)
-p 选项:导出格式化的脚本代码
把 awk 脚本的执行逻辑(包括 BEGIN、处理过程、END)格式化后保存到文件,方便调试复杂脚本。
示例:导出脚本执行逻辑
# 执行一个包含BEGIN、处理行、END的脚本,用--profile导出逻辑到文件
[bq@shell ~]$ awk --profile '
BEGIN { printf"---|Header|--\n" } # 开头打印表头
{ print } # 打印每一行
END { printf"---|Footer|---\n" } # 结尾打印表尾
' employee.txt > /dev/null # 重定向输出到/dev/null,只保留导出文件
导出的文件默认名为awkprof.out
,内容如下(包含执行次数和逻辑):
# gawk profile, created Mon Apr 3 14:37:37 2023# BEGIN块(执行1次)BEGIN {1 printf "---|Header|--\n"}# 处理行的逻辑(共5行数据,执行5次)5 {5 print}# END块(执行1次)END {1 printf "---|Footer|---\n"}
awk 内置变量 (常用)
awk 有很多内置变量,用于存储处理过程中的关键信息(比如当前行号、字段数)。用awk -d ''
可导出所有内置变量到awkvars.out
文件,以下是常用的几个:
变量 | 描述 | 例子(以employee.txt 第一行为例) |
---|---|---|
$0 | 表示当前行的完整内容 | $0 是 “1) 张三 技术部 23” |
$n | 表示当前行的第 n 个字段(n 为数字) | $2 是 “张三”,$3 是 “技术部” |
FS | 字段分隔符(默认是空格) | 用-F: 指定后,FS 为 “:” |
NF | 当前行的字段总数 | 第一行有 4 个字段,NF=4 |
NR | 当前处理的行号(从 1 开始) | 处理第一行时 NR=1,第五行时 NR=5 |
FNR | 当前文件内的行号(多文件时有用) | 处理第一个文件的第一行时 FNR=1 |
OFS | 输出字段分隔符(默认是空格) | 设为 “,” 后,打印$2和$3 时用逗号分隔 |
ORS | 输出记录分隔符(默认是换行) | 设为 “;” 后,每行输出结尾用分号代替换行 |
实例:内置变量的使用
1. 用 NR 打印行号
# 打印行号+当前行内容(NR为行号,$0为整行)
[bq@shell ~]$ echo -e "一 二\n一 二 三\n一 二 三 四" | awk '{ print NR". "$0 }'
1. 一 二
2. 一 二 三
3. 一 二 三 四
2. 用 NF 筛选字段数大于 2 的行
# 只打印字段数>2的行(NF是当前行的字段总数)
[bq@shell ~]$ echo -e "一 二\n一 二 三\n一 二 三 四" | awk 'NF > 2'
一 二 三
一 二 三 四
3. 用 OFS 修改输出分隔符
# 把输出分隔符设为"|",打印$2和$3(默认用空格分隔,现在用|)
[bq@shell ~]$ awk 'BEGIN {OFS="|"} {print $2, $3}' employee.txt
张三|技术部
李四|人力部
王五|行政部
赵六|技术部
朱七|客服部
awk 运算符 (常用)
awk 支持多种运算符,和其他编程语言类似,常用的有:
类型 | 运算符 | 说明 |
---|---|---|
赋值 | =、+=、-=、*=、/= | 例如 x+=2 等价于 x=x+2 |
算术 | +、-、*、/、%(取余) | 例如 5%2=1 |
自增 / 自减 | ++、– | x++(先使用 x 再 + 1)、++x(先 + 1 再使用 x) |
关系 | <、<=、>、>=、==(等于)、!=(不等于) | 例如 x>10 判断 x 是否大于 10 |
正则匹配 | (匹配)、!(不匹配) | $3 ~ / 技术 / 表示第 3 个字段包含 “技术” |
逻辑 | &&(与)、||(或)、!(非) | 例如 x>0 && x<10 判断 x 是否在 0-10 之间 |
示例:运算符的使用
1. 赋值运算符
# 演示各种赋值运算(BEGIN块中直接执行,不处理输入)
[bq@shell ~]$ awk 'BEGIN { x=5; x+=2; print "x+=2后:"x }' # x=5+2=7
x+=2后:7[bq@shell ~]$ awk 'BEGIN { x=5; x*=2; print "x*=2后:"x }' # x=5*2=10
x*=2后:10
2. 逻辑运算符
# 逻辑与(&&):判断num是否在0-7之间
[bq@shell ~]$ awk '
BEGIN {num=5if (num>=0 && num<=7) # 5>=0且5<=7,条件成立{ print "0<="num"<=7" }
}'
0<=5<=7 # 条件成立,输出结果
# 逻辑非(!):判断字符串是否为空
[bq@shell ~]$ awk '
BEGIN { site = "" # 空字符串if (! length(site)) # length(site)=0,!0为真{ print "site是空字符串" }
}'
site是空字符串 # 条件成立,输出结果
3. 正则匹配运算符
# 匹配第3个字段(部门)包含“技术”的行
[bq@shell ~]$ awk '$3 ~ /技术/ { print $2"在"$3 }' employee.txt
张三在技术部
赵六在技术部
awk 输出重定向
awk 的输出(比如print
或printf
的结果)可以重定向到文件或通过管道传给其他命令,类似 Shell 的重定向。
覆盖重定向 >
把输出写入文件,覆盖文件原有内容(如果文件不存在则创建)。
# 先创建一个有内容的文件
[bq@shell ~]$ echo "旧内容:Hello World!" > /tmp/message.txt
[bq@shell ~]$ cat /tmp/message.txt
旧内容:Hello World!# 用>重定向,覆盖原有内容
[bq@shell ~]$ awk 'BEGIN { print "新内容:Hello awk!" > "/tmp/message.txt" }'
[bq@shell ~]$ cat /tmp/message.txt
新内容:Hello awk! # 原有内容被覆盖
追加重定向 >>
把输出追加到文件末尾,保留原有内容。
# 先创建一个有内容的文件
[bq@shell ~]$ echo "旧内容:Hello World!" > /tmp/message.txt
[bq@shell ~]$ cat /tmp/message.txt
旧内容:Hello World!# 用>>追加内容到末尾
[bq@shell ~]$ awk 'BEGIN { print "新内容:Hello awk!" >> "/tmp/message.txt" }'
[bq@shell ~]$ cat /tmp/message.txt
旧内容:Hello World!
新内容:Hello awk! # 新内容追加在后面
管道 |
把 awk 的输出通过管道传给其他命令处理。
# 用tr命令把小写字母转为大写(awk的输出作为tr的输入)
[bq@shell ~]$ awk 'BEGIN { print "hello, world!" | "tr [a-z] [A-Z]" }'
HELLO, WORLD! # tr处理后的结果
双向管道 |&
建立 awk 与外部命令的双向通信(既可发送数据给外部命令,也可接收外部命令的返回结果)。
示例:用 tr 转换大小写后,再读取结果
[bq@shell ~]$ awk 'BEGIN {cmd = "tr [a-z] [A-Z]" # 定义外部命令:转大写print "hello, world!" |& cmd # 发送数据给tr命令close(cmd, "to") # 关闭向tr的输入cmd |& getline out # 从tr接收处理结果,存到outprint out # 打印结果close(cmd) # 关闭双向管道
}'
HELLO, WORLD! # 输出转换后的结果
如涉及版权问题,请联系作者处理!!!