1. 前言:为什么要学命令行参数?
上一篇我们学了awk的基础运行方式,但只能处理简单的文本(默认以空格/制表符为分隔符)。实际工作中,我们处理的文本可能很复杂——比如以逗号、冒号为分隔符的日志文件、CSV文件,或者需要提前定义变量、加载脚本库,这时候就需要用到awk的命令行参数。
根据上传的资料,awk(gawk)有很多命令行参数,我们重点讲解日常工作中最常用、最实用的10个,每个参数都配详细示例,确保你学完就能用。
提示:所有示例依然基于我们的测试文件test.txt,若你没有,可先执行以下命令创建:
echo -e "张三 20 男\n李四 25 女\n王五 30 男" > test.txt
另外,我们新增一个CSV文件test.csv(以逗号为分隔符),用于测试分隔符相关参数:
echo -e "姓名,年龄,性别,城市\n张三,20,男,北京\n李四,25,女,上海\n王五,30,男,广州" > test.csv
2. 必学参数1:-F(指定字段分隔符,最常用)
参数说明:
-F FS(全称:--field-separator FS):指定文本的“字段分隔符”,FS是你要指定的分隔符(比如逗号、冒号、空格)。
默认情况下,awk会以「空格或制表符」为分隔符,将一行文本拆分成多个字段($1、$2、$3...)。但如果文本是CSV格式(逗号分隔)、日志格式(冒号分隔),默认分隔符就失效了,这时候必须用-F指定。
语法格式:
awk -F "分隔符" '脚本内容' 文件名
实操示例(重点掌握):
# 示例1:处理CSV文件(逗号分隔),打印第1列(姓名)和第4列(城市)
awk -F "," '{print $1, $4}' test.csv
# 输出结果:
# 姓名 城市
# 张三 北京
# 李四 上海
# 王五 广州
# 示例2:跳过CSV文件的第一行(表头),只打印数据行的姓名和年龄
# 模式:NR>1(NR表示行号,NR>1即跳过第1行)
awk -F "," 'NR>1 {print $1, $2}' test.csv
# 输出:
# 张三 20
# 李四 25
# 王五 30
# 示例3:指定冒号为分隔符(模拟日志文件)
# 先创建一个模拟日志文件log.txt
echo -e "root:x:0:0:root:/root:/bin/bash\nbin:x:1:1:bin:/bin:/sbin/nologin" > log.txt
# 用-F指定冒号分隔,打印用户名($1)和家目录($6)
awk -F ":" '{print "用户名:"$1, "家目录:"$6}' log.txt
# 输出:
# 用户名:root 家目录:/root
# 用户名:bin 家目录:/bin
# 示例4:指定多个分隔符(用[]包裹,匹配任意一个)
# 比如文本中既有空格又有逗号,用-F "[ ,]"表示“空格或逗号”都作为分隔符
echo -e "张三,20 男\n李四 25,女" > test2.txt
awk -F "[ ,]" '{print $1, $2, $3}' test2.txt
# 输出:
# 张三 20 男
# 李四 25 女
补充:上传资料中提到,-F的长选项是--field-separator,用法完全一致,比如 awk --field-separator "," '{print $1}' test.csv,和-F ","效果一样,日常用-F更简洁。
3. 必学参数2:-v(提前定义变量,实用)
参数说明:
-v VAR=VAL(全称:--assign VAR=VAL):在awk程序执行之前,提前定义一个变量VAR,并给它赋值VAL。
关键作用:变量可以在脚本中直接使用,适合需要固定值、批量修改参数的场景(比如定义一个阈值、固定字符串),避免重复修改脚本内容。
注意点:-v只能定义一个变量,如果需要定义多个变量,就多次使用-v(比如 -v a=1 -v b=2)。
实操示例:
# 示例1:定义变量threshold=25,打印年龄大于threshold的行
awk -v threshold=25 -F "," 'NR>1 {if($2>threshold) print $1, "年龄:"$2}' test.csv
# 输出(只有王五年龄大于25):
# 王五 年龄:30
# 示例2:定义多个变量,批量添加前缀和后缀
awk -v prefix="用户:" -v suffix="(已验证)" '{print prefix$1 suffix}' test.txt
# 输出:
# 用户:张三(已验证)
# 用户:李四(已验证)
# 用户:王五(已验证)
# 示例3:结合条件判断,用变量过滤内容
# 定义变量gender="女",只打印女性用户
awk -v gender="女" -F "," 'NR>1 && $3==gender {print $1, $4}' test.csv
# 输出:
# 李四 上海
补充(避坑):上传资料中提到,用-v定义awk的内置变量(比如FS、NR)可能会有意外结果,因为awk会根据需要重置内置变量的值,所以尽量用-v定义自定义变量(比如threshold、gender)。
4. 必学参数3:-f(执行脚本文件,上一篇补充)
参数说明:
-f SOURCE-FILE(全称:--file SOURCE-FILE):指定awk脚本文件,执行该文件中的脚本内容处理文本。
上一篇我们简单讲过,这里结合上传资料补充两个实用细节:
可以多次使用-f选项,执行多个脚本文件(脚本内容会被拼接在一起执行);
脚本文件中,会默认添加@namespace "awk"(无需手动添加,不影响使用)。
实操示例(补充进阶用法):
# 示例1:创建两个脚本文件,用-f多次执行
# 脚本1:filter.awk(筛选男性用户)
$3=="男" {
print $1, $2}
# 脚本2:format.awk(添加前缀)
{
print "男性用户:"$0}
# 执行两个脚本(先筛选,再格式化,顺序影响结果)
awk -F "," -f filter.awk -f format.awk test.csv
# 输出:
# 男性用户:张三 20
# 男性用户:王五 30
# 示例2:结合-v和-f,动态传递变量到脚本文件
# 修改filter.awk脚本,使用自定义变量threshold
if($2>threshold) {
print $1, $2}
# 用-v定义threshold=20,执行脚本
awk -v threshold=20 -F "," -f filter.awk test.csv
# 输出(跳过表头,年龄大于20的用户):
# 李四 25
# 王五 30
5. 必学参数4:-e(命令行指定多个脚本片段)
参数说明:
-e PROGRAM-TEXT(全称:--source PROGRAM-TEXT):在命令行中指定一段脚本内容,和直接写在单引号里的脚本类似,但支持多次使用-e,拼接多个脚本片段。
适用场景:脚本逻辑比较复杂,拆分成多个片段更清晰,或者需要结合-f脚本文件和命令行脚本片段。
注意点(上传资料重点提醒):awk 5.0版本之后,每个-e指定的脚本片段必须是完整的语法单元,不能拆分不完整的语句(比如不能把一个if语句拆成两个-e片段)。
实操示例:
# 示例1:多次使用-e,拼接脚本片段(筛选+格式化)
awk -F "," -e 'NR>1' -e '$3=="男"' -e '{print "姓名:"$1, "城市:"$4}' test.csv
# 拆解:
# -e 'NR>1':跳过表头
# -e '$3=="男"':筛选男性用户
# -e '{print ...}':格式化输出
# 输出:
# 姓名:张三 城市:北京
# 姓名:王五 城市:广州
# 示例2:结合-f和-e,补充脚本逻辑
# 用-f执行filter.awk(筛选年龄>20),用-e补充格式化输出
awk -v threshold=20 -F "," -f filter.awk -e '{print "年龄超标:"$1, $2}' test.csv
# 输出:
# 年龄超标:李四 25
# 年龄超标:王五 30
# 示例3:错误示范(5.0+版本报错)——拆分不完整语句
# 以下命令会报错,因为if语句被拆成两个-e片段
awk -e 'BEGIN {a=5;' -e 'print a}'
# 正确写法:要么写在一个-e里,要么写在单引号里
awk -e 'BEGIN {a=5; print a}' # 正确,输出5
6. 必学参数5:-E(执行脚本文件,终止选项解析)
参数说明:
-E FILE(全称:--exec FILE):和-f类似,都是执行脚本文件,但有两个关键区别:
-E会终止选项解析,也就是说,-E后面的所有命令行参数,都会直接传递给awk程序,不会被当作awk的选项;
-E不允许在命令行中进行变量赋值(比如 VAR=VALUE 这种形式)。
适用场景:主要用于CGI脚本(网页应用),防止恶意用户传递非法选项或变量,日常工作中用得不多,但需要了解。
实操示例:
# 示例1:用-E执行脚本文件,后面的参数会被传递给awk(而非选项)
# 创建脚本file.awk:打印ARGV数组(存储命令行参数)
BEGIN {
for(i=0;i<ARGC;i++) print "ARGV["i"]="ARGV[i]}
# 用-E执行,后面加参数test.csv -v a=1(这些参数会被传递给ARGV)
awk -E file.awk test.csv -v a=1
# 输出(-v a=1没有被当作选项,而是作为参数传入):
# ARGV[0]=awk
# ARGV[1]=file.awk
# ARGV[2]=test.csv
# ARGV[3]=-v
# ARGV[4]=a=1
# 示例2:用-f执行,后面的-v a=1会被当作选项(对比差异)
awk -f file.awk test.csv -v a=1
# 输出(-v a=1被当作选项,没有传入ARGV):
# ARGV[0]=awk
# ARGV[1]=test.csv
7. 必学参数6:-b(按字节处理字符,解决乱码)
参数说明:
-b(全称:--characters-as-bytes):让awk将所有输入数据当作“单字节字符”处理,输出也按单字节处理。
适用场景:处理包含非UTF-8编码(比如GBK)的文本,或者文本中存在无效多字节字符(导致awk解析错乱、乱码)时,用-b可以避免乱码问题。
默认情况下,awk会根据系统的locale(区域设置)处理多字节字符(比如中文UTF-8是3字节),如果文本编码和locale不匹配,就会出现乱码,这时候用-b参数就能解决。
实操示例(模拟乱码场景):
# 示例:处理GBK编码的中文文本(假设系统locale是UTF-8,默认会乱码)
# 先创建一个GBK编码的文件gbk.txt(用iconv转换编码)
echo "张三 20" | iconv -f UTF-8 -t GBK > gbk.txt
# 默认情况下,awk读取会乱码
awk '{print $1}' gbk.txt
# 输出(乱码):锘垮皬
# 用-b参数,按字节处理,避免乱码(前提是你知道文本编码,后续可转换)
awk -b '{print $1}' gbk.txt
# 输出(正确显示GBK编码的张三,需确保终端支持GBK显示):张三
8. 必学参数7:-c(兼容模式,禁用GNU扩展)
参数说明:
-c(全称:--traditional):启用“兼容模式”,禁用gawk的所有GNU扩展功能,让gawk的行为和原始的BWK awk(最早的awk版本)保持一致。
适用场景:编写可移植的awk脚本(比如需要在非GNU系统,如Solaris、AIX上运行),避免使用gawk独有的扩展功能,导致脚本在其他系统上报错。
实操示例(对比扩展功能的差异):
# 示例:gawk独有的扩展功能——数组排序(asort函数)
# 默认情况下(非兼容模式),可以使用asort
awk 'BEGIN {arr[1]=3; arr[2]=1; arr[3]=2; asort(arr); for(i=1;i<=3;i++) print arr[i]}'
# 输出(排序后):1 2 3
# 用-c参数启用兼容模式,禁用asort函数,会报错
awk -c 'BEGIN {arr[1]=3; arr[2]=1; arr[3]=2; asort(arr); for(i=1;i<=3;i++) print arr[i]}'
# 输出(报错,提示asort未定义):awk: cmd. line:1: fatal: function `asort' not defined
9. 必学参数8:-P(严格POSIX模式)
参数说明:
-P(全称:--posix):启用“严格POSIX模式”,不仅禁用gawk的GNU扩展,还禁用所有POSIX标准不允许的扩展功能,比-c(兼容模式)更严格。
关键区别:-c只是禁用gawk独有的扩展,而-P会禁用所有不符合POSIX标准的扩展,同时还有一些额外限制(比如换行不能跟在?或:后面)。
注意点:如果同时指定-c和-P,-P会生效(优先级更高),gawk会给出警告。
实操示例:
# 示例1:POSIX模式下,-Ft不会将FS设为制表符(对比兼容模式)
# 兼容模式(-c):-Ft会将FS设为制表符
awk -c -Ft '{print FS}' test.txt | cat -A # cat -A显示制表符(^I)
# 输出:^I(制表符)
# POSIX模式(-P):-Ft不会将FS设为制表符,FS就是字符t
awk -P -Ft '{print FS}' test.txt | cat -A
# 输出:t
# 示例2:POSIX模式下,换行不能跟在?后面(语法错误)
# 非POSIX模式,允许换行跟在?后面
awk 'BEGIN {a=5; print a>3?"大于3":"小于3"}'
# 输出:大于3
# POSIX模式,换行跟在?后面会报错
awk -P 'BEGIN {a=5; print a>3?
"大于3":"小于3"}'
# 输出(报错):awk: cmd. line:1: BEGIN {a=5; print a>3?
# awk: cmd. line:1: ^ unexpected newline or end of string
10. 必学参数9:-d(导出全局变量到文件)
参数说明:
-d[FILE](全称:--dump-variables[=FILE]):将awk程序中所有全局变量的类型、最终值,输出到指定文件中;如果不指定FILE,默认输出到awkvars.out文件。
适用场景:调试复杂awk脚本时,查看全局变量的值,排查变量赋值错误、变量名拼写错误(比如把i写成j)。
注意点:-d和FILE之间不能有空格(比如-dvar.out,不能写成-d var.out)。
实操示例:
# 示例1:默认输出到awkvars.out
# 编写一个带全局变量的脚本,统计男性用户数量
awk -d -F "," 'NR>1 {if($3=="男") count++} END {print "男性用户数:"count}' test.csv
# 执行后,会生成awkvars.out文件,查看文件内容:
cat awkvars.out
# 输出(包含所有全局变量,重点看count):
# ARGC=2
# ARGV[0]="awk"
# ARGV[1]="test.csv"
# count=2 # 男性用户数为2,正确
# ...(其他内置变量)
# 示例2:指定输出文件为vars.txt
awk -dvars.txt -F "," 'NR>1 {if($3=="女") count++} END {print "女性用户数:"count}' test.csv
# 查看vars.txt文件
cat vars.txt
# 输出:count=1(女性用户数为1,正确)
11. 必学参数10:-h(查看帮助信息)
参数说明:
-h(全称:--help):打印gawk的帮助信息,包括所有命令行参数的说明、用法示例,适合忘记某个参数用法时快速查询。
实操示例:
# 查看gawk帮助信息
awk -h
# 输出内容(截取部分):
# Usage: awk [POSIX or GNU style options] -f script-file [--] file ...
# Options:
# -v VAR=VAL assign VAL to VAR before execution
# -F FS use FS for field separator
# -f FILE read script from FILE
# -e 'program-text' use program-text as script
# -b, --characters-as-bytes treat all input as single-byte characters
# -c, --traditional run in compatibility mode (disable GNU extensions)
# ...(其余参数说明)
12. 小结与练习
本篇我们讲解了awk最常用的10个命令行参数,配了可直接运行的示例,重点牢记:
-F:指定分隔符(处理CSV、日志必备);
-v:提前定义变量(调试、批量处理必备);
-f/-e:执行脚本(简单脚本用-e,复杂脚本用-f);
-b/-P:解决乱码、编写可移植脚本;
-d:调试变量,-h:查看帮助。
课后练习:
用-F参数处理log.txt(冒号分隔),打印用户名($1)和登录shell($7);
用-v定义变量city="北京",筛选test.csv中城市为北京的用户,并用-e参数拼接格式化输出脚本;
用-f创建一个脚本,统计test.csv中所有用户的年龄总和,并用-d参数导出总和变量到文件。
下一篇,我们将讲解awk的高级用法——内置变量(NR、NF、ARGC等)、内置函数、流程控制(if、for、while),还有环境变量、文件包含等进阶功能,帮你彻底精通awk,应对各种复杂文本处理场景!