本文转载自微信公众号「Linux开发那些事儿」,作者LinuxThings。转载本文请联系Linux开发那些事儿公众号。
在 Bash 解释器中,内置了许多变量,这些变量的功能是解释器自带的,我们在编写shell脚本时如果能灵活的使用它们,对脚本的编写效率以及差错大有帮助, 下面一一介绍这些变量
$FUNCNAME、$LINENO、$PWD
FUNCNAME和LINENO 变量经常用于脚本的调试
FUNCNAME 表示当前函数的名字,作用范围仅限函数中使用,在函数外无值
LINENO 表示当前所在脚本中变量出现在的行号
PWD 表示当前目录, 对应于 pwd命令
现有个脚本 a.sh 内容如下
- 1 #!/bin/bash
- 2
- 3
- 4 testa()
- 5 {
- 6 echo 'func='$FUNCNAME,$LINENO
- 7 }
- 8
- 9
- 10 testa
- 11
- 12 echo 'lineno:'$LINENO
- 13 echo 'xx:'$FUNCNAME
- 14 echo 'curpath:'$PWD
执行 ./a.sh 命令, 输出如下
- [tt@ecs-centos-7 ~]$ ./a.sh
- func=testa,6
- lineno:12
- xx:
- curpath:/home/tt
在 testa 函数中 FUNCNAME 变量值是 testa,也即函数名字,在函数外部无值
LINENO 变量无论是在函数中还是函数外,都表示当前所在的行号
$$、$PPID
这两个变量依次表示当前进程ID和父进程ID
现有 a.sh 脚本,内容如下
sleep 20 睡眠语句是为了让执行脚本进程暂缓退出,在另一个终端中验证输出的结果
- #!/bin/bash
- #set -u
-
- echo 'cur pid:'$$
- echo 'parent pid:'$PPID
- sleep 20
在当前终端执行 ./a.sh,结果如下
- [tt@ecs-centos-7 ~]$ ./a.sh
- cur pid:13095
- parent pid:12982
在执行a.sh的脚本进程退出之前,打开另一个终端,执行 ps -o pid,ppid,time,cmd -p 12982,13095 命令,结果如下
- [tt@ecs-centos-7 ~]$ ps -o pid,ppid,time,cmd -p 12982,13095
- PID PPID TIME CMD
- 12982 12981 00:00:00 -bash
- 13095 12982 00:00:00 /bin/bash ./a.sh
从上面的结果可以看出, 执行 ./a.sh 命令之后,$$ 变量表示的是 执行a.sh脚本的进程ID 13095 ,而 12982 是它的父进程ID,也即是 PPID变量的值,它是当前bash的实例
$0,$1,$2...$n、$#
$# 表示从命令行传入脚本的参数数量
$0,$1,$2...$n 是从命令行传递到脚本的参数 $0 是脚本本身的名字 $1 是第一个参数 $2 是第二个参数,依此类推 $n 是第n个参数
第十个参数及以后的参数必须要用大括号括起来,例如: ${10}、${11}、${12} 依次表示第十个变量、第十一个变量、第十二个变量
$*、$@
都表示位置参数,不过它们之间也有些不同点
使用 $* 时,如果加上双引号,即 "$* " 的形式,那所有位置的参数会被当作一个单词来处理,如果不包含双引号,即 $* 的形式,则每个位置的参数都被当作一个独立的单词来处理
而对于 $@,无论是否加上双引号,每个位置的参数都被当作一个独立的单词来处理
现有c.sh, 内容如下
- #!/bin/bash
-
- cnt=1
- echo 'test 1111'
-
- for var in "$*"
- do
- echo "arg$cnt="$var
- let "cnt+=1"
- done
- echo
-
- cnt=1
- echo 'test 2222'
- for var in $*
- do
- echo "arg$cnt="$var
- let "cnt+=1"
- done
- echo
-
- cnt=1
- echo 'test 3333'
- for var in "$@"
- do
- echo "arg$cnt="$var
- let "cnt+=1"
- done
- echo
-
- cnt=1
- echo "test 4444"
- for var in $@
- do
- echo "arg$cnt="$var
- let "cnt+=1"
- done
执行 ./c.sh 1 2 3,结果如下
- [root@ecs-centos-7 ~]# ./c.sh 1 2 3
- test 1111
- arg1=1 2 3
-
- test 2222
- arg1=1
- arg2=2
- arg3=3
-
- test 3333
- arg1=1
- arg2=2
- arg3=3
-
- test 4444
- arg1=1
- arg2=2
- arg3=3
从上面的结果可以看出,对于 $* 来说,加了双引号之后所有位置参数就会被视为一个单词
对于 $@ 来说,是否加双引号,结果都是一样的
所以,仅在使用双引号时,$*和 $@ 才会有差异
$?
命令、函数或者脚本的退出状态,在判断命令的执行结果或者函数的调用结果时很有用处
现有 e.sh 和 f.sh 测试脚本
e.sh 脚本
- #!/bin/bash
-
- test_func()
- {
- if [[ $1 -eq 10 ]]; then
- return 5
- fi
- return 6
- }
-
-
- if [ $# -ge 1 ]; then
- name="$1"
- shift 1
- $name "$@"
- fi
f.sh 脚本
- #!/bin/bash
-
-
- sh e.sh test_func 3
- echo 'exit code1:'$?
-
- sh e.sh test_func 10
- echo 'exit code2:'$?
-
- test -f $PWD/xx.txt
- echo 'exit code3:'$?
-
- test -f $PWD/e.sh
- echo 'exit code4:'$?
执行 ./f.sh 命令,结果如下
- [root@ecs-centos-7 ~]# ./f.sh
- exit code1:6
- exit code2:5
- exit code3:1
- exit code4:0
脚本 e.sh 中 test_func 函数功能是:当参数等于10时,退出状态为 5,否则为 6
sh e.sh test_func 3 命令会调用 e.sh 脚本中的 test_func函数,传入参数是 3,所以退出状态为 6,同理可知, sh e.sh test_func 10 命令的退出状态是 5
在Linux中,命令执行成功,退出状态为 0 ,失败则为非 0
test -f $PWD/xx.txt 命令是检查当前目录是否存在 xx.txt 文件,因当前目录并不存在 xx.txt,所以命令执行失败,退出状态为非 0
由于e.sh 存在于当前目录下,所以 test -f $PWD/e.sh 命令执行成功,退出状态为 0
$IFS
此变量用于 Bash 识别字符串或单词边界,默认值是空格,脚本中根据需要可以修改此变量的值
现有 b.sh脚本,内容如下
- #!/bin/bash
-
- va="a:b:c"
- vb="x-y-z"
- vc="e,f,g"
-
- IFS=":"
- echo 'va:'$va
- echo 'vb:'$vb
- echo 'vc:'$vc
-
- echo
-
- IFS="-"
- echo 'va:'$va
- echo 'vb:'$vb
- echo 'vc:'$vc
-
- echo
-
- IFS=","
- echo 'va:'$va
- echo 'vb:'$vb
- echo 'vc:'$vc
执行 ./b.sh 结果如下
- [tt@ecs-centos-7 ~]$ ./b.sh
- va:a b c
- vb:x-y-z
- vc:e,f,g
-
- va:a:b:c
- vb:x y z
- vc:e,f,g
-
- va:a:b:c
- vb:x-y-z
- vc:e f g
从结果可以看出,当 $IFS 为 : 时,字符串 "a:b:c"被解析成 a b c
当 $IFS 为 - 时,字符串 "x-y-z"被解析成 x y z
当 $IFS 为 , 时,字符串 "e,f,g"被解析成 e f g
$HOME、$USER、$UID、$GROUPS
- HOME: 用户home目录
- USER: 当前用户名
- UID: 当前用户ID
- GROUPS: 当前用户组ID
- [tt@ecs-centos-7 ~]$ echo $HOME
- /home/tt
- [tt@ecs-centos-7 ~]$ echo $USER
- tt
- [tt@ecs-centos-7 ~]$ echo $UID
- 1003
- [tt@ecs-centos-7 ~]$ echo $GROUPS
- 1003
$HOSTTYPE、$MACTYPE、$OSTYPE
这些变量都表示系统硬件
- [tt@ecs-centos-7 ~]$ echo $HOSTTYPE
- x86_64
- [tt@ecs-centos-7 ~]$ echo $MACHTYPE
- x86_64-redhat-linux-gnu
- [tt@ecs-centos-7 ~]$ echo $OSTYPE
- linux-gnu
小结
本文介绍了一些常用的 Bash 内置变量,对于一些生僻或者平常很少用到的变量可以自行查阅相关资料