一、AWK 核心定位
AWK 是文本处理/轻量数值计算编程语言,诞生初衷处理表格文本,内置:变量、循环、判断、浮点运算、数组、格式化输出。 你前面代码用到的是 AWK 最常用场景:纯数学计算(无需读文件) + Shell 传参。 三大主流实现:
gawk(GNU awk,Linux 默认,功能最全,支持^幂、sqrt等)mawk(轻量,嵌入式常用)nawk(BSD/macOS 默认)
二、基础命令格式
awk [选项] '匹配规则{执行代码}' 输入文件/数据流两大特殊代码块(重中之重)
BEGIN{ ... }- 在读取任何输入行之前执行仅1次
- 无输入文件、只做计算、初始化变量专用,你那段代码就是用它
END{ ... }- 在读完所有输入行之后执行仅1次
- 常用于汇总统计(求和、计数、平均值)
行处理主体 pattern{action}
无BEGIN/END时,awk会逐行读取输入,每行执行一次{action}
pattern:匹配条件(正则、数值判断、布尔),省略则匹配所有行action:要执行的代码,省略则默认打印整行print $0
三、常用启动选项(你代码用到 -v)
| 选项 | 作用 | 示例 |
|---|---|---|
-v var=val | 外部传参:Shell变量 → AWK内部变量 | awk -v h=32 -v w=32 'BEGIN{print h*w}' |
-F "分隔符" | 指定列分隔符,默认空格/制表符 | -F "," 处理csv;`-F " |
-f script.awk | 从文件读取awk脚本,不写在行内 | awk -f calc.awk data.txt |
-W math | 开启高级数学函数(gawk) | sqrt() log() exp() |
-v 补充说明
Shell 变量无法直接在单引号awk脚本中访问,必须用 -v 注入:
# 错误,$SAMPLE_H 在单引号内不会被shell解析
awk 'BEGIN{print $SAMPLE_H}'
# 正确,-v 把shell变量传给awk内部h变量
awk -v h="$SAMPLE_H" 'BEGIN{print h}'四、AWK 内置变量(高频)
1. 输入行相关(读文件时用)
| 变量 | 含义 |
|---|---|
$0 | 当前完整一行文本 |
$1,$2,$3... | 当前行第1、2、3列(按-F分隔) |
NF | 当前行列总数 Number of Fields |
NR | 已读取总行数 Number of Records |
FS | 输入分隔符(等价-F) |
OFS | print输出时的列分隔符,默认空格 |
2. 数学/全局内置(你计算代码用到)
| 标识 | 功能 |
|---|---|
^ | 幂运算,x^0.5 = 开平方,x^-0.5 = 1/√x |
int(x) | 截断取整(直接舍弃小数,非四舍五入)int(11.9)=11 |
sqrt(x) | 平方根,等价x^0.5 |
print | 输出内容到stdout,会被shell $(awk)捕获 |
; | 语句分隔符,同一块内多条语句隔开 |
五、分模块语法详解
1. 纯计算场景(对应你 PRE_LEN 代码,无文件输入)
只使用 BEGIN{},不需要传入任何文件,专门做浮点运算
# 示例复刻你的逻辑
SAMPLE_H=32
SAMPLE_W=32
PRE_LEN=$(awk -v h="$SAMPLE_H" -v w="$SAMPLE_W" '
BEGIN{
s = (h * w) ^ -0.5; # s = 1/sqrt(hw)
ph = int(h * 16 * s);
pw = int(w * 16 * s);
print ph * pw; # 输出计算结果
}
')
echo $PRE_LEN # 输出256等价简化写法(一行压缩):
PRE_LEN=$(awk -v h=$SAMPLE_H -v w=$SAMPLE_W 'BEGIN{print int(h*16/sqrt(h*w)) * int(w*16/sqrt(h*w))}')2. 读取文件/数据流(文本处理通用)
示例1:按空格分割,打印第1、3列
# test.txt内容:aa 123 bb 456
awk '{print $1, $3}' test.txt
# 输出 aa bb示例2:匹配过滤,只打印第二列大于100的行
awk '$2 > 100 {print $0}' test.txt示例3:BEGIN初始化 + 行循环累加 + END汇总
统计文件第二列总和
awk '
BEGIN{sum=0}
{sum += $2}
END{print "总和=" sum}
' test.txt3. 运算符体系
数学运算符
+ - * / % ^ 加减乘除取模幂
++ -- 自增自减
= += -= 赋值复合运算
比较运算符
> < >= <= == != 数值相等判断
~ !~ 正则匹配 $1 ~ /abc/ 第一列包含abc
逻辑运算符
&& 与、|| 或、! 非
4. 控制流:if / for / while
if 判断
BEGIN{
a=20
if(a > 16){
print "大于16"
}else{
print "小于等于16"
}
}for 循环
BEGIN{
total=0
for(i=1;i<=10;i++){
total += i
}
print total # 1~10求和
}5. 内置数学函数(gawk)
BEGIN{
print sqrt(1024); # 平方根
print int(16.99); # 截断取整16
print log(2.718); # 自然对数
print exp(1); # e^x
print sin(3.14/2); # 三角函数(弧度)
}六、Shell 与 AWK 交互核心技巧
1. 捕获awk输出赋值变量(你代码 $(awk))
$(命令) 叫命令替换:执行内部命令,把标准输出字符串取出,赋值给shell变量
VAL=$(awk 'BEGIN{print 100+56}')
echo $VAL # 1562. 多行续行符 \
shell行尾\表示换行只是排版,逻辑是同一行命令:
# 换行拆分,可读性高
PRE_LEN=$(awk -v h="$SAMPLE_H" \
-v w="$SAMPLE_W" \
'BEGIN{print int(h*16/sqrt(h*w))*int(w*16/sqrt(h*w))}')3. 引号规则(避坑重点)
- awk脚本必须用单引号包裹:
'code'- 双引号会让shell提前解析
$、\等符号,破坏awk语法
- 双引号会让shell提前解析
- shell变量传递只能用
-v,不能直接在awk内写$SAMPLE_H - awk内部打印字符串用双引号:
print "结果=", val
七、高频实用示例(工程常用)
示例1:快速计算任意数学表达式(替代bc)
shell原生不支持浮点运算,awk是最简方案
# 计算平方根
awk -v n=1024 'BEGIN{print sqrt(n)}'
# 小数乘法
awk 'BEGIN{print 32 * 16 / sqrt(32*64)}'示例2:批量统计文件夹文件大小
ls -l | awk 'BEGIN{sum=0} NR>1 {sum+=$5} END{print "总字节:",sum}'示例3:过滤日志,提取错误行并计数
# 打印包含error的行,最后输出错误总数
awk '/error/ {print $0; cnt++} END{print "错误行数:" cnt}' app.log八、针对你那段代码的踩坑总结
- 不能去掉
-v:去掉后awk无法读取h/w,计算为0,PRE_LEN=0,生成逻辑崩溃 - 不能用
sqrt(h*w)替代(h*w)^-0.5:效果等价,但^写法更贴合原模型公式 int()是截断不是四舍五入:矩形分辨率会导致ph*pw≠256,不能硬编码256- 必须
BEGIN{}:没有输入文件,不写BEGIN代码不会执行,PRE_LEN为空 - 行尾
\仅排版:删除后整行写在一起功能完全不变,仅可读性下降
九、极简记忆思维导图
awk 调用结构
├─ 选项:-v 传参 / -F 分隔符
├─ 脚本块
│ ├─ BEGIN{}:预处理/纯计算(无输入必用)
│ ├─ pattern{action}:逐行处理文件
│ └─ END{}:收尾汇总统计
└─ 输出捕获:shell $(awk ...) 存到变量