Shell 命令之变量与传参

0.总览

在 Shell 中定义的变量,默认就是全局变量,可使用 local 定义局部变量

1. 脚本传参

在 shell 脚本中,可以直接使用如下的预置符号,直接获取传入的参数,以及一些脚本元数据

  • $0: 脚本本身文件名称
  • $1: 命令行第一个参数,$2为第二个,以此类推
  • $*: 所有参数列表
  • $@: 所有参数列表
    • ${@:2}: 从第2个开始,输出剩下的
    • ${@:3:1}: 从第3个开始,输出1个
  • $#: 参数个数
  • $$: 脚本运行时的PID
  • $?: 脚本退出码

2. @ 的区别

两者均表示获取全部的参数列表,但使用时还有一些区别,二者没有被引号括起来时行为一致,当一旦在被括号括起来时:

  • "$*" : 将所有传参看成一个参数
  • "$@" : 将每个参数都看作独立的

我们编写脚本进行说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/bash

echo "Show param from \"\$*\""
for var in "$*"
do
echo "$var"
done

echo "Show param from \"\$@\""
for var in "$@"
do
echo "$var"
done

调用命令为 sh test_param.sh 1 2 3,其结果为

1
2
3
4
5
6
Show param from "$*"
1 2 3
Show param from "$@"
1
2
3

3. ${ }

1. 变量替换

$var${var} 本身是没有区别的,但是用 ${} 会比较精确的界定变量名称的范围。

1
2
3
A=Linux
echo $AB #表示变量AB
echo ${A}B #表示变量A后连接着B,即LinuxB

2. 变量替换形式

  • ${var} : 变量本来的值
  • ${var:-word} : 如果变量 var 为空或已被删除(unset),那么返回 word,但不改变 var 的值。
  • ${var:=word} : 如果变量 var 为空或已被删除(unset),那么返回 word,并将 var 的值设置为 word。是一种赋值默认值的常见做法
  • ${var:?word} : 如果变量 var 为空或已被删除(unset),那么将消息 word 送到标准错误输出,可利用此特性来检查是否设置了变量的值。若此替换出现在 Shell 脚本中,那么脚本将停止运行。
  • ${var:+word} : 如果变量 var 被定义,那么返回 word,但不改变 var 的值。

4. $()$(()) 和 ``(反引号)

  • $() 等同于 ``(反引号): 运行一段命令,$() 的弊端是,并不是所有的类 unix 系统都支持这种方式,但反引号是肯定支持的
  • $(()) 进行数字运算
1
2
a=3;b=2;c=5
echo $((a+b*c)) # 13

5. 单引号与双引号

  • 单引号属于强引用,它会忽略所有被引起来的字符的特殊处理,被引用起来的字符会被原封不动的使用,单引号字串中不能出现单引号(对单引号使用转义符后也不行)
  • 双引号属于弱引用,它会对一些被引起来的字符进行特殊处理
1
2
3
4
[root@host ]$ echo '$(echo hello world)'
[root@host ]$ $(echo hello world)
[root@host ]$ echo "$(echo hello world)"
[root@host ]$ hello world

6. BASH_SOURCEdirname

BASH_SOURCE[0] : 等价于 BASH_SOURCE,取得当前执行的 shell 文件所在的路径及文件名
dirname : 去除文件名中的非目录部分,仅显示与目录有关的部分

/home/abc/test.sh 内容如下:

1
2
3
4
5
#!/bin/bash
echo "${BASH_SOURCE[0]}"
echo "${BASH_SOURCE}"
echo "$(dirname "${BASH_SOURCE[0]}")"
echo "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

若在目录 /home 下执行 sh ./abc/test.sh,输出为:

1
2
3
4
abc/test.sh
abc/test.sh
abc/
/home/abc

7. SHLVL

SHLVL代表shell打开的深度,进程第一次打开shell时$SHLVL=1,然后在此shell中再打开一个shell时$SHLVL=2

8. 注意

  1. ${BASH_SOURCE-$0}:获取当前执行的脚本文件的全路径。
  2. 获取当前执行脚本名,如果是 sh 或者 ./ 的运行方式,直接使用 $0,如果是 source 的方式运行,$0就变成了 -bash 了。因为 source 命令,不再产生新的shell,而是在当前shell下执行一切命令。此时需要使用 $BASH_SOURCE