当前位置: 首页 > news >正文

第5.7节:awk赋值运算

1 第5.7节:awk赋值运算

  赋值是一种表达式,它会把一个(通常是不同的)值存储到变量中。例如,我们把值 1 赋给变量 z

z = 1

  执行该表达式后,变量 z 的值为 1 。z 在赋值前的任何旧值都会被丢弃。

  赋值操作也可存储字符串值。例如,以下代码会把 "this food is good" 存储到变量 message 中:

thing = "food"
predicate = "good"
message = "this " thing " is " predicate

  这也体现了字符串拼接。= 符号被称为赋值运算符。它是最简单的赋值运算符,因为右侧操作数的值会原封不动地存储起来。大多数运算符(加法、拼接等)只有在计算值时才有用;若值不用,使用运算符就没必要。而赋值运算符不同:它会产生一个值(即便你忽略该值),但赋值操作会通过修改变量产生副作用(side effect )。

  赋值操作的左侧操作数不一定是变量(见 6.1.3 节《变量》,第 128 页 );也可以是字段(见 4.4 节《修改字段内容》,第 73 页 )或数组元素(见第 8 章《awk 中的数组》,第 181 页 )。这些都被称作左值(lvalues),即它们可出现在赋值运算符左侧。右侧操作数可以是任意表达式;它会生成要存储到指定变量、字段或数组元素里的新值(这类值被称作右值(rvalues) )。

  需注意,变量没有固定类型。变量的类型就是最后一次赋给它的值的类型。看下面的程序片段,变量 foo 起初是数值类型,之后变成字符串类型:

foo = 1
print foo
foo = "bar"
print foo

  第二次赋值给 foo 字符串值后,它之前的数值类型就被遗忘了。

  未以数字开头的字符串值,数值类型为 0 。执行以下代码后,foo 的值为 5 :

foo = "a string"
foo = foo + 5

注意:把变量先当数字用、后当字符串用容易造成混淆,属于不良编程风格。前面两个示例只是说明 awk 的工作机制,并非推荐的编程方式!

  赋值是一种表达式,所以它有值——就是被赋的值。比如,z = 1 是一个值为 1 的表达式。由此可衍生出连续赋值写法,像这样:

x = y = z = 5

  这个示例会把值 5 存入 xyz 三个变量。原理是:z = 5 的值为 5 ,会存入 y ;接着 y = z = 5 的值(也是 5 )会存入 x

  赋值操作可在任何需要表达式的地方使用。例如,编写 x != (y = 1) 来把 y 设为 1 ,然后测试 x 是否等于 1 ,这是合法的。但这种风格往往会让程序难以阅读;除非是在一次性(one-shot )程序中,否则应避免嵌套赋值。

  除了 = ,还有几种其他赋值运算符,它们会结合变量的旧值进行算术运算。比如,+= 运算符会把右侧的值加到变量的旧值上,计算出新值。因此,以下赋值操作会把 foo 的值加 5 :

foo += 5

这等价于:

foo = foo + 5

用哪种写法取决于哪种能让程序含义更清晰。

  有些情况下,使用 +=(或任何赋值运算符 )和简单重复左侧操作数在右侧表达式中,结果并不相同。例如:

# 感谢 Pat Rankin 提供此示例
BEGIN {foo[rand()] += 5for (x in foo)print x, foo[x]bar[rand()] = bar[rand()] + 5for (x in bar)print x, bar[x]
}

  bar 的下标几乎肯定不同,因为每次调用 rand() 都会返回不同的值。(数组和 rand() 函数尚未讲到。更多信息见第 8 章《awk 中的数组》,第 181 页,以及 9.1.3 节《数值函数》,第 198 页 )。这个示例说明了赋值运算符的一个重要特性:左侧表达式只会求值一次

至于先对左侧还是右侧表达式求值,由具体实现决定。看下面这个示例:

i = 1
a[i += 2] = i + 1

a[3] 的值可能是 2 ,也可能是 4 。

  下表列出了算术赋值运算符。在每种情况下,右侧操作数是一个表达式,其值会被转换为数字。

运算符作用
lvalue += incrementincrement(增量)加到 lvalue 的值上
lvalue -= decrementlvalue 的值中减去 decrement(减量)
lvalue *= coefficientlvalue 的值乘以 coefficient(系数)
lvalue /= divisorlvalue 的值除以 divisor(除数)
lvalue %= moduluslvalue 的值设为其对 modulus(模数)取余的结果
lvalue ^= powerlvalue 的值求 power(幂次)次方
lvalue **= powerlvalue 的值求 power(幂次)次方(c.e. 可能是特定语境缩写,无特殊说明可忽略 )

表 6.2:算术赋值运算符

注意:POSIX 标准仅规定了 ^= 运算符。为实现最大程度的可移植性,请勿使用 **= 运算符。

1.1.1 /= 与正则表达式之间的语法歧义

  /= 赋值运算符和首字符为 = 的正则表达式常量之间存在语法歧义。这在一些商业版本的 awk 中尤为明显。例如:

$ awk /==/ /dev/null
<kbd>error</kbd> awk: syntax error at source line 1
<kbd>error</kbd> context is
<kbd>error</kbd>    >>> /= <<<
<kbd>error</kbd> awk: bailing out at source line 1

一种变通方法是:

awk '/[=]=/' /dev/null

gawk 不存在此问题;BWK awk 和 mawk 也不存在该问题 。


作者声明:本文用于记录和分享作者的学习心得,可能有部分文字或示例来自AI平台,如:豆包、DeepSeek(硅基流动)(注册链接)等,由于本人水平有限,难免存在表达错误,欢迎留言交流和指教!
Copyright © 2022~2025 All rights reserved.

http://www.lryc.cn/news/626960.html

相关文章:

  • 技术半衰期悖论:AI时代“不可替代领域“的深耕地图
  • AIStarter服务器版深度解析:与桌面版对比,解锁云端AI开发新体
  • 如何代开VSCode的settigns.json文件
  • 【JavaEE】多线程(线程安全问题)
  • Gin传参和接收参数的方式
  • BM25 系列检索算法
  • 自学大语言模型之Transformer的Trainer
  • 工业电脑选得好生产效率节节高稳定可靠之选
  • 0基础安卓逆向原理与实践:第5章:APK结构分析与解包
  • 华为仓颉语言的class(类)初步
  • 比剪映更轻量!SolveigMM 视频无损剪切实战体验
  • 将集合拆分成若干个batch,并将batch存于新的集合
  • ubuntu下安装vivado2015.2时报错解决方法
  • 换根DP(P3478 [POI 2008] STA-StationP3574 [POI 2014] FAR-FarmCraft)
  • Qt 中最经典、最常用的多线程通信场景
  • 通过自动化本地计算磁盘与块存储卷加密保护数据安全
  • 链表-24.两两交换链表中的结点-力扣(LeetCode)
  • ansible playbook 实战案例roles | 实现基于firewalld添加端口
  • SSM从入门到实战:2.1 MyBatis框架概述与环境搭建
  • 【LeetCode 热题 100】279. 完全平方数——(解法三)空间优化
  • innovus auto_fix_short.tcl
  • 代码随想录Day57:图论(寻宝prim算法精讲kruskal算法精讲)
  • 3D检测笔记:相机模型与坐标变换
  • 今日行情明日机会——20250820
  • 算法提升树形数据结构-(线段树)
  • 数据结构与算法系列(大白话模式)小学生起点(一)
  • 关于 Flask 3.0+的 框架的一些复习差异点
  • 算法230. 二叉搜索树中第 K 小的元素
  • 雷卯针对香橙派Orange Pi 5B开发板防雷防静电方案
  • 力扣hot100:最大子数组和的两种高效方法:前缀和与Kadane算法(53)