提出问题
今天,小王问了一个脚本问题。
小王问到:
这个脚本为啥扫不出所有的
小红说到:
ip和端口打印出来是啥
小王:
在脚本里面echo 变量是正常打印的
花狗看了小王的回答之后,说到:
小红接着说到:
xargs 无法解析 {20..23}
分析问题
为什么他们有不同的看法吗?
那么我们来分析下他们三个是从哪些角度来思考这个问题的。
小王角度
-
从脚本
portscan.sh
里面可以看到,作者通过输入重定向<
将文件ip.txt
传给命令read
读取其文件内容的每一行,由于变量$IFS
的作用,可以将文件的每一行拆分多个字段:文本第一行: 192.168.1.1 {20..23} 通过read: 192.168.1.1 --> IP {20..23} --> PORT 即定义并赋值两个变量: IP=192.168.1.1 PORT={20..23}
好了,到了这里,
echo $PORT
会打印出来什么呢?答案是:
是的,
echo
将{20..23}
打印出来了!这是不是跟我们的echo {20..23}
很像呢?
那这是一样的东西吗?
结果不一样!!
前面
echo $PORT
正是小王说 :–在脚本里面echo 变量是正常打印的– 原因。他的思考角度:
echo $PORT 等价于 echo {20..23} | 值:{20..23}
花狗角度
-
这么一看,好像是这么一回事。跑脚本后却有了 <–这个脚本为啥扫不出所有?–> 这样的问题!
那是因为变量赋值时
PORT={20..23}
:{20..23} 以一串字符整体地传给了 变量PORT, 实际上: {20..23} ---> '{20..23}' ----> PORT 等价于 输出 那么: echo $PORT -------> echo '{20..23}' -------> {20..23}
这正是花狗的思考角度。
那为什么变量赋值的等号右边是以字符形式传给变量名的呢?
实际上,在shell中,变量数据类型是: * 字符 * 数值 也就是说: 从赋值那一刻开始,字符就带上了`引号`,我们的一些特殊字符不再有它的特殊含义,只有字面值的意义。
那真的是这样子吗?
我们来看一个例子:
这时用
echo
打印出它们值结果会是怎么样呢?我们来看一下:
结果是一样的!!!
这也是印证了 从赋值那一刻开始,字符首尾就带上了
引号
,我们的一些特殊字符不再有它的特殊含义,只是字面值的意义。空口无凭,有何依据呢?
在
bash.info
文档中的shell 参数
中提到,变量赋值语句的规则:得知:变量的值是可以是一个"名字"(即字符字面上的意义),或是一个数字
而字符是以引号引起来的,只是shll在变量赋值的时候帮你把字符用引号引来:
单双引号也说明了,引号里的字符保留引号中所有字符的字面值,其中包括作为关键字的花括号
{}
:以及 花括号扩展使用文档中的说明:
大致总结的意思:
格式正确的`大括号扩展`必须包含未加引号的左括号和右括号, 以及至少一个未加引号的逗号或一个有效的序列表达式。 任何不正确的大括号展开都将保持不变。 `{` 或 `,` 可以用反斜杠括起来,以防止被认为是大括号表达式的一部分。 为了避免与参数展开冲突,字符串 `${` 被认为不符合花括号展开条件, 并在闭合 `}`之前抑制花括号展开。
综合以上变量赋值、引号作用、花括号作用,得出下面实践结果一样:
小红角度
- 小红的思考角度大概也是清楚了在这脚本中
{20..23}
是作为一个整体字符串使用的,而xargs
也是没有解析这串字符的功能。
综上总结
- shell变量的数据类型是字符和数字。
- 用引号括起来的符号扩展(如花括号扩展)是不能进行扩展的。
优化脚本
小王的脚本
小王开始还在纠结能否让加了引号的 {} 进行展开:
但很快,他用了其他方法实现了他想要的功能:
花狗的脚本
花狗认真地看了小王的脚本,起初想:用awk
将-
作为分隔符,再用=~
来作匹配判断,结合seq
,这就实现了需求!
嗯~角度新颖,甚是巧妙!
但扭头一想:没必要将 -
作为分隔符啊!read
可以接收多个参数,不止两个呢!而且,这个脚本甚是啰嗦,且阅读性较差,编写脚本应该尽可能地先以阅读性高且代码量少为实践理念。
脚本的阅读性差,会导致其他人甚至作者本身看脚本费劲且容易出错,这也是花狗为什么要认真地看小王脚本的原因!
花狗思考片刻,从seq
和read
两个命令的功能入手,优化了脚本是这样的:
给文件增加可读性可以这样子:
这样看起来,易读性非常好,代码量也少,非常便于维护。