那些 Shell、Awk 中自动隐式类型转换的“坑”
时间:2022-04-28
本文章向大家介绍那些 Shell、Awk 中自动隐式类型转换的“坑”,主要内容包括1、问题:、2、结论:、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。
1、问题:
在林林总总的编程语言里,弱类型的语言着实不少,一方面这种“动态类型”用起来很方便,而另一方面则“坑”你没商量~ 常见的 SQL、Shell、Awk 都会遇到各种暗藏的“隐式类型转换”,稍不留神就会“掉坑”。下面就列举一些 shell、awk 里的自动隐式类型转换 case,防止掉坑。
- 注意 shell、awk 的变量为空 字符串、变量为空 未定义、初始值的隐式转换问题:
# shell 下的字典排序比较
root@localhost 10:59:23 /opt/script >
[[ (( a > 0 )) ]] && echo 1
1
root@localhost 10:59:34 /opt/script >
[[ (( 00 > 0 )) ]] && echo 1
1
# 双括号不做算术比较,而是字符串的字典比较,等同于 [[]]
[[ (( 0 == 0 )) ]] && echo 1
1
root@localhost 13:04:27 /opt/script >
[[ (( 11 > 110 )) ]] && echo 1
root@localhost 13:04:34 /opt/script >
# shell 的字符串比较不做转换,严格按照字面量字典比较
root@localhost 11:51:41 /opt/script >
[[ a == "" ]] && echo 1
root@localhost 14:00:53 /opt/script >
[[ a > "" ]] && echo 1
1
root@localhost 14:00:59 /opt/script >
[[ a > 0 ]] && echo 1
1
# shell 的数字类型隐式转换:变量未定义会被转换为 0
root@localhost 11:53:56 /opt/script >
[[ a -eq 0 ]] && echo 1
1
root@localhost 11:54:11 /opt/script >
[[ a1 -eq 1 ]] && echo 1
root@localhost 11:55:11 /opt/script >
[[ 1a -eq 1 ]] && echo 1
-bash: [[: 1a: value too great for base (error token is "1a")
# awk 隐式类型只转换 1a,不转换 a1
root@localhost 11:55:15 /opt/script >
echo|awk '{print 1a == 1 }'
1
# awk 外置变量未定义会被置为空字符串,且空字符串不会隐式转换为数字
root@localhost 14:12:57 /opt/script >
echo|awk -va= '{print a == 0 }'
0
root@localhost 14:18:08 /opt/script >
echo|awk '{print "" == 0 }'
0
root@localhost 14:13:01 /opt/script >
echo|awk -va= '{print a == "" }'
1
# awk 内置变量未定义默认会隐式转换为数字 0 或者空字符串
root@localhost 14:13:12 /opt/script >
echo|awk '{print a == 0 }'
1
root@localhost 14:13:48 /opt/script >
echo|awk '{print a == "" }'
1
# awk 内置变量在比较时,一方加了双引号,则最终结果当做字符串比较(未定义的变量还是会自动隐式转换)
root@localhost 14:23:43 /opt/script >
echo|awk '{print 0b == "00" }'
0
root@localhost 14:23:47 /opt/script >
echo|awk '{print 0b == 00 }'
1
root@localhost 14:36:57 /opt/script >
echo|awk '{print "00" == 0 }' # 明确标识字符串的不再隐式转换为数字
0
# awk 中的隐式转换:无论最终结果是否以数字比较,未定义的变量都会自动隐式转换
root@localhost 14:27:49 /opt/script >
echo|awk '{print 0b == "0" }'
1
echo|awk '{y=0b; print y == "0" }'
1
echo|awk '{print 0b == 0 }'
1
echo|awk '{y="0b"; print y == "0" }'
0
echo|awk '{y="0b"; print +y == "0" }'
1
Jun@VAIO 23:49:55 ~ >
echo|awk '{y="0b"; print +y == "00" }'
0
Jun@VAIO 23:49:59 ~ >
echo|awk '{y="0b"; print (+y > "00") }'
0
Jun@VAIO 23:50:14 ~ >
echo|awk '{y="0b"; print +y < "00" }'
1
root@localhost 14:41:16 /opt/script >
echo|awk '{print "00"a == "00" }'
1
# awk 的外置变量参与比较时,与内置变量的隐式转换特性不同,如果数字中含有非数字字符串则直接被当做字符串。
# 也就是说 awk 外置变量不具有内置变量对 非数字字符隐式转换 的特性
root@localhost 16:16:27 /opt/script >
a=0b; echo|awk -vm="$a" '{print m; print m == 0; print int(m) == 0 }'
0b
0
1
root@localhost 16:16:39 /opt/script >
a=00; echo|awk -vm="$a" '{print m; print m == 0; print int(m) == 0 }'
00
1
1
root@localhost 16:16:59 /opt/script >
a=00; echo|awk -vm="$a" '{print m; print m == "0"; print int(m) == "0" }'
00
0
1
root@localhost 16:20:11 /opt/script >
a=00; echo|awk -vm="$a" '{print m; print m == "00"; print int(m) == 0 }'
00
1
1
Jun@VAIO 00:33:24 ~ >
a=0b; echo|awk -vm="$a" '{b=0;print 0b; print 0b == 0; print int(m) == 0 }'
00
0
1
# 为避免上述 case 的各种歧义和不确定性,还是老老实实的用 +、int 强制转换吧~
Jun@VAIO 00:43:55 ~ >
echo|awk '{print int("1/*")}'
1
Jun@VAIO 00:47:31 ~ >
echo|awk '{print int("*/1")}'
0
Jun@VAIO 00:47:38 ~ >
echo|awk '{print +"*/1"}'
0
Jun@VAIO 00:47:47 ~ >
echo|awk '{print +"1/*"}'
1
Jun@VAIO 00:47:53 ~ >
2、结论:
(1)shell 的自动隐式类型转换相当弱,而 awk 相对而言容错性好 (2)从 case 来看,如果单纯的靠 shell、awk 的自动隐式类型转换相当不靠谱,极其容易出错, (3)为获得确定的结果,还是老老实实的强制转换吧,比如 awk 中使用 +、int 等。
- Kafka源码系列之kafka如何实现高性能读写的
- Kafka源码系列之分组消费的再平衡策略
- Kafka源码系列之Consumer高级API性能分析
- Kafka源码系列之源码解析SimpleConsumer的消费过程
- Spark调优系列之序列化方式调优
- Spark源码系列之foreach和foreachPartition的区别
- kafka源码系列之mysql数据增量同步到kafka
- Hbase源码系列之BufferedMutator的Demo和源码解析
- Kafka源码系列之0.10版本的Producer源码解析及性能点讲解
- Spark源码系列之spark2.2的StructuredStreaming使用及源码介绍
- Hbase源码系列之scan源码解析及调优
- spark源码系列之内部通讯的三种机制
- Hbase源码系列之regionserver应答数据请求服务设计
- 大数据基础系列之kafkaConsumer010+的多样demo及注意事项
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 由一个系统激活工具引起的一次简单测试
- Golang channel 快速入门
- 潘石屹用Python解决100个问题 | 素数
- Spring 自动装配模式之构造函数装配方式
- 安全狗 {safedog} 最新版注入bypass
- C语言定时关机小程序
- 深入k8s:Pod对象中重要概念及用法
- Golang语言排序的几种方式
- 性能分析(1)- Java 进程导致 CPU 使用率升高,问题怎么定位?
- 安全服务之安全基线及加固(三)Apache篇
- 使用docsify来管理文献
- Cypress系列(41)- Cypress 的测试报告
- SSRF绕过
- 性能测试必备知识(6)- 如何查看“CPU 上下文切换”
- flex布局 div盒子居中