首页 > 编程笔记 > Linux命令 阅读:8

Shell命令行参数(位置参数)的用法

运行 Shell 脚本时,我们可以往脚本中传递一些自定义参数,这些参数在脚本内部可以使用 $n 的形式来接收。例如,$1 表示第一个参数,$2 表示第二个参数,依次类推。这种通过 $n 的形式来接收的参数在 Shell 脚本中叫作命令行参数,也称位置参数。

简单来说,命令行参数的意义就在于可以让我们往 Shell 脚本中传递一些参数,脚本接收到这些参数后可以做一些预设的操作。

我们知道,变量的名字必须以字母或者下划线开头,不能以数字开头。而命令行参数的命名方式却偏偏是数字,这与变量的命名规则相冲突,所以我们将其视为“特殊变量”。除了 $n 之外还有其他特殊参数:$#、$*、$@、$? 和 $$ 等,这里先简单了解一下,下文会展开讲解。

命令行参数变量包括下面 4 种:

图 1 命令行参数

命令行参数的用法有两种:
【实例】给 Shell 脚本文件传递命令行参数。
[root@linux opt]# vim demo1.sh

#!/bin/bash
echo "语言: $1"
echo "网址: $2"

[root@linux opt]# bash demo1.sh shell c.biancheng.net
语言: shell
网址: c.biancheng.net
其中,Shell是第一个命令行参数,c.biancheng.net是第二个命令行参数,参数与参数之间以空格进行分隔。

给函数传递命令行参数:
[root@linux opt]# vim demo2.sh

#!/bin/bash
# 定义函数
function func(){
    echo "语言: $1"
    echo "网址: $2"
}
# 调用函数并传入命令行参数
func shell https://c.biancheng.net

[root@linux opt]# bash demo2.sh
语言: shell
网址: https://c.biancheng.net
如果需要传入的参数太多,达到或者超过了 10 个,就需要用 ${n} 的方式来接收,例如,${10}、${23}。

{ } 的作用是帮助 bash 解释器识别参数的边界,这跟使用变量时加 { } 是一样的。

Shell特殊变量

Shell 特殊变量具体见下表:

表:Shell特殊变量及其含义
变量 含义
$0 当前 Shell 脚本名称/当前脚本本身
$n 传递给脚本或函数的参数。n 是数字,表示第几个参数。例如,第一个参数是 $1、第二个参数是 $2……依此类推
$# 传递给脚本或函数的参数个数
$* 传递给脚本或函数的所有参数,将所有的参数看作一个整体
$@ 传递给脚本或函数的所有参数,将每个参数区分开对待
$? 获取上个命令的退出状态或函数的返回值。返回 0 表示命令执行成功,返回除 0 以外的任何其他数字都表示命令执行失败。
$$ 当前 Shell 进程的 ID 号(PID),对于 Shell 脚本而言就是这些脚本所在的进程 ID。

接下来通过案例,分别以给 Shell 脚本传递参数和给函数传递参数的方式来验证上述几个特殊变量。

【实例】给 Shell 脚本传递参数。
[root@linux opt]# vim demo3.sh
#!/bin/bash
echo "当前进程的 ID 号(PID):$$"
echo "此 Shell 脚本的名称:$0"
echo "第一个参数:$1"
echo "第二个参数:$2"
echo "全部的参数(方式一):$@"
echo "全部的参数(方式二):$*"
echo "所有参数个数:$#"
rm -rf $0

[root@linux opt]# chmod +x demo3.sh

[root@linux opt]# ./demo3.sh Shell c.biancheng.net
当前进程的 ID 号(PID):3516
此 Shell 脚本的名称:./demo3.sh
第一个参数:Shell
第二个参数:c.biancheng.net
全部的参数(方式一):Shell c.biancheng.net
全部的参数(方式二):Shell c.biancheng.net
所有参数个数:2

[root@linux opt]# echo $?
0

[root@linux opt]# ./demo3.sh
-bash: ./demo3.sh: 没有那个文件或目录

[root@linux opt]# echo $?
127
通过案例可以看到各特殊变量在 Shell 脚本中的不同效果,这里再给大家介绍一个小技巧:Shell 脚本的最后一行是“rm-rf $0”,作用是删除此 Shell 脚本,Shell 脚本在执行完成后将自己删除(删除时注意脚本文件本身的位置)。

给函数传递参数:
[root@linux opt]# vim demo4.sh
#!/bin/bash
# 定义函数
function func(){
    echo "语言: $1"
    echo "网址:$2"
    echo "第一个参数:$1"
    echo "第二个参数:$2"
    echo "全部的参数(方式一):$@"
    echo "全部的参数(方式二):$*"
    echo "所有参数个数:$#"
}

# 调用函数
func Shell https://c.biancheng.net

[root@linux opt]# chmod +x demo4.sh
[root@linux opt]# ./demo4.sh
语言:Shell
网址:https://c.biancheng.net
第一个参数:Shell
第二个参数:https://c.biancheng.net
全部的参数(方式一):Shell https://c.biancheng.net
全部的参数(方式二):Shell https://c.biancheng.net
所有参数个数:2
通过上述两个示例可以发现,$*$@都表示传递给函数或脚本的所有参数,乍一看没什么不同,但是它们之间是有区别的。当$*$@不被双引号" "包围时,它们之间没有任何区别,都是将接收到的每个参数看作一份数据,彼此之间以空格来分隔。

但是当它们被双引号" "包含时,就有区别了:
比如传递了 5 个参数,对于"$*"来说,这 5 个参数会合并到一起形成一份完整的数据,它们之间是无法分割的;而对于"$@"来说,这 5 个参数之间是相互独立的,它们是5份数据。

如果使用 echo 命令直接输出"$*""$@"变量的值进行对比是看不出区别的;但如果使用 for 循环逐个输出变量的值,立即就能看出区别,我们写一个 Shell 脚本试一下:
[root@linux opt]# vim demo5.sh
#!/bin/bash
echo "print each param from \"$*\""
for value in "$*"
do
    echo "$value"
done

echo "print each param from \"$@\""
for value in "$@"
do
    echo "$value"
done

[root@linux opt]# chmod +x demo5.sh
[root@linux opt]# ./demo5.sh a b c d e f
print each param from "$*"
a b c d e f
print each param from "$@"
a
b
c
d
e
f
从运行结果可以发现,对于"$*",只循环了 1 次,因为它只有 1 份数据;而对于"$@",循环了 6 次,因为它有 6 份数据,这就是两者加了双引号后的区别。

相关文章