sed与awk-第九章-函数
第九章 函数
算术函数
表9‑1 awk内置算术函数
| awk函数 | 描述 |
|---|---|
cos(x) |
返回x的余弦,x单位是弧度 |
exp(x) |
返回自然常数 e 的 x 次幂 |
int(x) |
截取整数部分,直接丢掉小数,不做四舍五入 |
log(x) |
返回x自然对数(以e为底) |
sin(x) |
返回x的正弦,x单位是弧度 |
sqrt(x) |
返回x的平方根(x≥0) |
atan2(y, x) |
返回 y/x 的反正切,结果范围 -π ~ π |
rand() |
返回伪随机浮点数,范围:0 ≤ r < 1,无参数 |
srand(x) |
设置rand()随机数种子;不带参数使用系统时间做种子;返回旧种子值 |
三角函数注意点
sin()、cos()参数是弧度,不是角度。角度转弧度公式:角度 * (pi / 180)atan2(0, -1)→ 得到 πexp(1)→ 得到 e ≈ 2.71828
int() 整数截取
只是截断小数,不是四舍五入;想要四舍五入用printf的
%.0f格式
输出:
随机数 rand() / srand()
- 如果脚本不调用srand():awk启动使用固定种子,每次运行rand()出来的随机序列完全一样,适合测试,不适合真正随机。
srand()不带参数:使用当前系统时间作为种子,每次运行得到不同随机序列。srand(数字):手动指定固定种子,可以复现同一套随机结果。
示例 rand.awk
前两次rand()是默认固定种子,每次运行结果不变;执行
srand()之后随机序列改变。
生成指定范围随机数公式
获取 1 ~ TOPNUM 之间的整数:
|
|
拆解:
rand()→0 ~ 0.99999rand() * TOPNUM→0 ~ TOPNUM‑0.99999int(...)→ 取整数部分0 ~ TOPNUM‑1+1→ 最终范围1 ~ TOPNUM
简单示例 pick1.awk
调用示例:awk -v TOPNUM=100 '...' 输出1‑100随机整数。
lotto彩票选号示例(去重随机数)
需求:选出NUM个1~TOPNUM之间不重复随机数。
核心技巧:用数组pick[select]保存已经选出来的数字;用select in pick判断数字是否已经存在,如果存在就重新生成。
|
|
缺陷:输出结果无序;原书后续自定义sort函数解决排序。 补充:把pick数组转普通数字下标数组,方便排序:
字符串函数
表9‑2 awk内置字符串函数
| awk函数 | 描述 |
|---|---|
gsub(r,s,t) |
在t中将正则r全部替换为s;返回替换次数;省略t默认$0 |
index(s,t) |
返回子串t在s的起始位置,找不到返回0;字符串位置从1开始 |
length(s) |
返回字符串s字符长度;省略参数默认$0 |
match(s,r) |
在s匹配正则r,返回匹配起始位置;无匹配返回0;设置内置变量RSTART、RLENGTH |
split(s,a,sep) |
用分隔符sep把s切分到数组a;返回元素个数;省略sep使用FS |
sprintf(fmt,expr…) |
和printf格式一样,不打印,返回格式化后的字符串,可以赋值变量 |
sub(r,s,t) |
在t把正则r第一次匹配替换成s;成功返回1,失败返回0;省略t默认$0 |
substr(s,p,n) |
从s的第p位截取子串;n是截取最大长度;省略n截取到字符串末尾 |
tolower(s) |
返回全部转小写的新字符串 |
toupper(s) |
返回全部转大写的新字符串 |
awk字符串下标从1开始,和C语言从0开始不一样!
sprintf()
printf直接输出;sprintf()生成字符串赋值变量。
示例,数字转ASCII字符:
index()、substr() 截取子串
index(s,t):查找子串,返回位置,找不到返回0
substr(s,p):从p位置截取到末尾
substr(s,p,n):截取n个字符
示例脚本caps.awk:把第一个单词首字母大写
length() 获取字符串长度
常用于判断行是否超过80字符,做文本断行处理。
sub() / gsub() 替换函数
sub():只替换第一次匹配,成功返回1,失败0gsub():全局全部替换,返回替换发生的总次数
- 第三个参数
t可选,不写默认操作$0 - 替换字符串里面
&代表匹配到的原文;想要字面&需要写\\& - awk没有sed那种空
//复用上次正则写法!
示例:替换全部UNIX为POSIX,只有发生替换才打印行
示例:troff字体替换
|
|
输入the UNIX operating system →输出 the \fBUNIX\fR operating system。
tolower()、toupper()大小写转换
返回新字符串,不会修改原字符串,需要赋值覆盖。
|
|
match()正则匹配,RSTART / RLENGTH
match(字符串,正则)
- 返回匹配起始位置;匹配失败返回0
- 匹配成功自动设置两个内置变量:
RSTART:匹配开始下标RLENGTH:匹配内容的字符长度;失败RLENGTH=-1
示例:提取行内匹配到的子串
注意参数顺序!
match(s,r),第一个参数字符串,第二个参数正则,和sub/gsub顺序相反,容易踩坑。
利用match循环提取所有大写连续字母片段:
自定义函数
awk允许自己写函数,提高代码复用。函数可以放在脚本任意位置,习惯写在脚本最开头。
语法格式
示例:insert(),在字符串指定位置后面插入子串
调用:
输入Hello →输出HellXXo
awk函数变量作用域(非常重要)
- 写在函数参数列表里的变量,是局部变量,函数外部访问不到。
- 函数体内直接创建的变量,默认是全局变量,脚本全部地方都可以访问。
- awk没有专门
local关键字;局部临时变量,写在参数列表的末尾,和真实参数空格隔开。
上面例子中
before_tmp, after_tmp仅仅放在参数列表,调用时不传值,它们就成为函数内部局部变量。
- 普通标量(数字、字符串)按值传递:函数拿到副本,不会修改外面原始变量。
- 数组是按引用传递:函数内部修改数组,外部原始数组同步被改变!
编写排序函数(插入排序)
数组传引用,函数内部直接修改原数组,不需要return返回数组。
调用方式:
完整演示:读取每行学生成绩,排序输出
|
|
维护函数库
- awk支持多个
‑f参数,可以加载多个脚本文件。可以把公共自定义函数放到单独.awk库文件。
|
|
sort.awk只存放sort函数定义,main.awk是业务脚本。
另一个排序的例子(处理man手册Related Commands)
业务需求:提取.SH "Related Commands"后面多行的命令列表,去除标点,排序后重新输出。
|
|
运行,需要同时加载sort函数库
|
|
第九章核心速记清单
- 算术函数
int()只截断小数,不四舍五入;三角函数参数是弧度。rand()返回[0,1);不调用srand()每次运行随机序列固定;srand()用时间做种子。- 获取1‑N随机整数公式:
1+int(rand()*N)。
- 字符串重要规则:awk字符串位置从1开始,不是0。
index(s,t)查找子串位置;substr(s,p,n)截取子串。sub()只替换第一个;gsub()全局替换;替换侧&代表匹配内容,无//复用正则。sprintf()生成格式化字符串,不直接打印,可以赋值变量。match(s,r):匹配正则,设置RSTART起始位置、RLENGTH匹配长度。注意参数顺序,字符串在前,正则在后。split()分割字符串到数组,返回元素个数。tolower() / toupper()返回转换后的副本,原字符串不变。
- 自定义函数
- 函数参数列表末尾放变量实现局部变量;函数内直接定义变量默认为全局。
- 普通变量按值传递;数组按引用传递,函数内修改外部数组跟着变。
return返回函数结果。
- 函数库:多
‑f选项加载多个awk脚本,把通用函数抽成独立库文件。
文章作者 会写代码的小郎中
上次更新 2011-08-08
许可协议 CC BY-NC-ND 4.0