Shell命令行参数(位置参数)的用法
运行 Shell 脚本时,我们可以往脚本中传递一些自定义参数,这些参数在脚本内部可以使用 $n 的形式来接收。例如,$1 表示第一个参数,$2 表示第二个参数,依次类推。这种通过 $n 的形式来接收的参数在 Shell 脚本中叫作命令行参数,也称位置参数。
简单来说,命令行参数的意义就在于可以让我们往 Shell 脚本中传递一些参数,脚本接收到这些参数后可以做一些预设的操作。
我们知道,变量的名字必须以字母或者下划线开头,不能以数字开头。而命令行参数的命名方式却偏偏是数字,这与变量的命名规则相冲突,所以我们将其视为“特殊变量”。除了 $n 之外还有其他特殊参数:$#、$*、$@、$? 和 $$ 等,这里先简单了解一下,下文会展开讲解。
命令行参数变量包括下面 4 种:

图 1 命令行参数
命令行参数的用法有两种:
【实例】给 Shell 脚本文件传递命令行参数。
给函数传递命令行参数:
接下来通过案例,分别以给 Shell 脚本传递参数和给函数传递参数的方式来验证上述几个特殊变量。
【实例】给 Shell 脚本传递参数。
给函数传递参数:
但是当它们被双引号
比如传递了 5 个参数,对于
如果使用 echo 命令直接输出
简单来说,命令行参数的意义就在于可以让我们往 Shell 脚本中传递一些参数,脚本接收到这些参数后可以做一些预设的操作。
我们知道,变量的名字必须以字母或者下划线开头,不能以数字开头。而命令行参数的命名方式却偏偏是数字,这与变量的命名规则相冲突,所以我们将其视为“特殊变量”。除了 $n 之外还有其他特殊参数:$#、$*、$@、$? 和 $$ 等,这里先简单了解一下,下文会展开讲解。
命令行参数变量包括下面 4 种:
- $n:n 为数字(见图 1),$0 表示 Shell 脚本本身(当前脚本名称),$1~$9 表示第一个到第九个参数,10 以上的参数建议使用大括号包含(${n})。
- $*:表示传递给脚本或函数的所有参数,$* 会将所有的参数看作一个整体。
- $@:表示传递给脚本或函数的所有参数,$@ 会把每个参数区分对待。
- $#:表示传递给脚本或函数的参数个数。

图 1 命令行参数
命令行参数的用法有两种:
- 给 Shell 脚本文件传递命令行参数(常用);
- 给函数传递命令行参数。
【实例】给 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 特殊变量具体见下表:变量 | 含义 |
---|---|
$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 份数据,这就是两者加了双引号后的区别。