1. Shell 参数概述
在 Shell 脚本编写中,我们为了使得程序灵活和无状态,有些变量我们不便于在脚本中写死,需要运用外部参数传递进去,每次传递的东西不一样,得到的结果也不尽相同,参数是与变量相辅相成的,将参数传递进 Shell 脚本中,也就成了变量,参数的使用使得我们的脚本更加的灵活和可扩展,同样也更易维护。
1.1 Shell 参数是什么
Shell 参数是我们在脚本文件外部传入的一系列参数,或是在 Shell 脚本中给函数传递的参数,其实质也就是上一节我们学习的变量,其与变量相辅相成,共同组成 Shell 脚本的一部分。
1.2 为什么要用参数
我们在变量一节知道了为什么利用变量,在此原因与变量类似,参数的使用使得我们的 Shell 脚本更加灵活,不需要在脚本中写死一些名称,根据用户的输出完成特定的功能,例如编写脚本计算 100 内数字的和,但是如果我们想计算 1000 呢?100000 呢?每次都需要修改脚本么,我们可以利用参数传递进计算脚本中,这样需要计算多少就由我们自己控制,这样的脚本也更加灵活,参数赋予脚本更强大的功能。
2. Shell 参数分类
我们知道了 Shell 中参数是什么,来看一下 Shell 脚本中参数的分类。
2.1 位置参数
位置参数顾名思义,就是传递给脚本参数的位置,例如给一个脚本传递一个参数,我们可以在 Shell 脚本内部获取传入的位置参数,获取参数的格式为:$n
。n 代表一个数字。例如传递给脚本的第一个参数就为 $1
,第 2 个参数就为 $2
, 以此类推……,其中 $0
为该脚本的名称。
在我们讲解变量的时候,变量的一条规范就是名字不能以数字开头,在此就是为了避免与 Shell 的位置参数相同引发异常。
例如:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
我们可以看到传递给 args1.sh
脚本两个位置参数,第一个为 python
, 第二个为 go
, 脚本名称为 args1.sh
2.2 特殊参数
在 Shell 中也存在特殊含义的参数如下表:
示例:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
我们能够通过上述例子看出,运行 curl -I baidu.com
的输出为 0,即为命令运行正常,获取到了正常的返回值;
$@
与 $*
看上去很像,都是传递给脚本或函数的所有参数;
$*
当被双引号 " "
包含时,所有的位置参数被看做一个字符串,我们用 for 循环遍历的时候可以看到输出为一行;
$@
当被双引号 " "
包含时,每个位置参数被看做独立的字符串,我们用 for 循环遍历的时候可以看到为每个字符串输出为单独的一行。
3. Shell 参数的使用
3.1 脚本传递
脚本传递参数,就是在运行脚本的时候通过位置参数传递进脚本内,每个参数利用一个空格来进行分割,如果传递的参数本身就有空格,则可以利用 ""
来引起来,作为一个整体传递,在脚本内通过 $n
来获取。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
例如我们第二个参数为一个带有空格的多个字符串,我们可以用双引号引起来作为一个位置参数进行传入。
3.2 函数传递
顾名思义,参数传递就是在函数外部进行参数的传入,由于函数部分在后续有专门章节详解,在此我们就以一个简单的示例进行说明。函数传递与脚本传递非常类似,只是在调用函数的时候进行传递位置参数即可,例如:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
在示例中,我们可以看到没有通过在脚本外部进行参数传递,而是在调用 show_args
函数的时候传入来两个参数。
4. 实例
4.1 需求
我们来做一个内网批量扫描可用 IP 脚本,用来判断某一个网段中的网络可达性。
4.2 思路
可以利用 ping
命令来检测可以 ping 通的 IP,将返回正常的内容记录在 success.log
中,失败的内容记录在 fail.log
中。
传递两个参数,第一个参数为网络前缀,例如 192.168.0.
,然后在脚本内部循环 1-255
来检测。
第二个参数为 ping 包的个数,如果包太多,时间花费太长,太短有可能造成误判,在此我们建议使用 2 个包来判断。
4.3 实现
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
当脚本运行完成后,可以在 /tmp/netlog/
目录下查看成功与失败的 IP 信息。
5. 注意事项
- 需要在实战中理解参数的特殊用处,在编写脚本中尽可能多用参数,使得脚本无状态;
- 需要理解
$@
与$*
两个的不同之处,在使用循环的时候需要格外注意; - 在利用位置参数传入脚本的时候,最好利用变量去接收传递的外部位置参数,便于我们在脚本内识别参数的具体含义。
6. 小结
参数与变量是相辅相成的,将变量传递进脚本或函数就为参数,脚本与变量配合使得我们的脚本更加通用,适应更广的需求。需要牢记特殊参数的形式,在后期的 Shell 编程中,这些参数是脚本编程的基石,只有基础牢靠,后续的使用才会得心应手,对上述的例子可以举一反三,例如探测某一个 IP 的所有端口是否开放等,在实际应用场景中熟悉各种参数的用法。