shell 之变量与传参

448 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第6天,点击查看活动详情

wiki

在初次接触 shell 脚本时,对于其中的一些符号的约定,总是有些迷惑,当遇到时就纪录下来,因此比较零碎。

1. 脚本传参

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

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

2. @ 的区别

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

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

我们编写脚本进行说明:

#!/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,其结果为

Show param from "$*"
1 2 3
Show param from "$@"
1
2
3

3. ${} 变量替换

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

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

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

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

5. 单引号与双引号

  • 单引号属于强引用,它会忽略所有被引起来的字符的特殊处理,被引用起来的字符会被原封不动的使用,单引号字串中不能出现单引号(对单引号使用转义符后也不行)
  • 双引号属于弱引用,它会对一些被引起来的字符进行特殊处理
[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 内容如下:

#!/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,输出为:

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