Shell变量(二)
参数展开
参数展开(parameter expansion)是shell提供变量值在脚本程序中使用的过程。缺省情况,未定义的变量会展开成null(空的)字符串。
有两种方式引用变量值:
$var
${var}
注:不要和命令替换操作$()
搞混。
展开运算符
分为替换运算符和模式匹配运算符。
- 替换运算符
替换运算符用于测试变量是否存在,且在某种情况下允许默认值(缺省值)的替换。比如,
当脚本需要根据用户输入位置参数来决定脚本执行行为时,为了防止用户执行时忘了在命令行上输入参数导致脚本运行出错,可以使用替换运算符得到一个缺省值备用。
运算符 | 替换 | 用途 |
---|---|---|
${varname:-value} | 如果varname存在且非null,则返回其值;否则,返回value | 如果变量未定义,返回默认值 |
${varname:=value} | 如果varname存在且非null,则返回varname的值;否则,设置varname值为value,并返回其值 | 如果变量未定义,则设置变量为默认值 |
${varname:?message} | 如果varname存在且非null,则返回它的值;否则,显示varname:message,并退出当前的命令或脚本 | 为了捕捉由于变量未定义所导致的错误 |
${varname:+value} | 如果varname存在且非null,则返回value;否则,返回null | 测试变量的存在 |
注1:以上每个运算符内冒号(:)都是可选的,如果省略冒号,则将每个定义中的“存在且非null”部分改为“存在”,即运算符仅用于测试变量是否存在,不测试其是否有值。
注2:varname前不需要加$
符号。
示例:
var=${count:-0}
echo $count # null ,由于count未定义,只返回默认值,但不对count赋值,所以仍为null
echo $var # 0,由于count未定义,默认返回0值,所以var值为0
var1=${count1:=0}
echo $count1 # 0,由于count1未定义,设置它值为缺省值,并将该值返回
echo $var1 #0,count1未定义,返回该值
${count2:?"undefined"} # count: undefined
count4=3
var2=${count4:+0} # 0,由于count4已定义,返回值0
count5= #变量只存在,但是null
var3=${count5-0} # 空值
- 模式匹配运算符
通常用来分割路径的组成部分,例如目录前缀、文件名后缀等。
运算符 | 替换 | 用途 |
---|---|---|
${variable#pattern} | 如果模式匹配变量值开头处,则删除匹配的最短部分,并返回剩下的部分 | ... |
${variable##pattern} | 如果模式匹配变量值的开头处,则删除匹配的最长部分,并返回剩下的部分 | 保留basename |
${variable%pattern} | 如果模式匹配变量值的结尾处,则删除匹配的最短部分,并返回剩下的部分 | 去除后缀 |
${variable%%pattern} | 如果模式匹配变量值的结尾处,则删除匹配的最长部分,并返回剩下的部分 |
注:
#
匹配前面,%
匹配后面;单个#
或%
匹配最短部分,两个匹配最长部分(贪婪算法)。- 模式
/*/
匹配任何位于两个斜杠之间的元素,.*
匹配点号后面接着的任何元素。
例:
path=/home/user/project/filename.txt
echo ${path#/*/} # 最短匹配/home/并删除,返回user/project/filename.txt
echo ${path##/*/} # 最长匹配/*/,返回filename.txt
echo ${path%.*} # 返回/home/user/project/filename
echo ${path%%.*} # 返回/home/user/project/filename
echo ${path##*.} # 提取后缀名,返回后缀txt
- 字符串变量长度
${#variable}
返回$variable
值里的字符长度。
echo ${#path} # 返回 31
对于数组变量,·${#array}
返回数组第一个元素长度。
- 子字符串提取和匹配替换
运算符 | 作用 |
---|---|
${var:pos} | 提取变量var的pos位置开始的字符串 |
${var:pos:len} | 提取变量var的pos位置开始的字符串,最大长度为len |
${var/pattern/replace} | var中第一个匹配pattern部分替换为replace |
${var//pattern/replace} | 所有匹配pattern部分替换为replace |
${var/#pattern/replace} | 如果var前缀匹配pattern,匹配部分替换为replace |
${var/%pattern/replace} | 如果var后缀匹配pattern,匹配部分替换为replace |
${!varprefix*} ,${!varprefix@} | 匹配前面以varprefix开始的已声明变量名称 |
示例:
var=abc123456789def
echo ${var:3} # 123456789def 从第3个偏移量开始输出
echo ${var:3:9} # 123456789
echo ${var/456/xyz} # abc123xyz789def
echo ${var/#abc/000} # 000123456789def
echo ${var/#123/000} # abc123456789def 没有前缀匹配,返回原值
filename=abc.txt
echo ${filename/%txt/grd} # abc.grd 替换后缀名
a=${!file*}
echo $a # filename
b=${!a}
echo $b # abc.txt 间接引用
位置参数
位置参数(positional parameter)指shell脚本的命令行参数,也表示shell函数内的函数参数。名称以单个整数命名。$0
指脚本名称,$1
是第一个参数,依次类推。当参数大于9个时,引用该参数时需要用{}
括起来。
值测试与模式替换运算符结合使用:
filename=${1:-/dev/tty}
使用内部变量对传递的参数个数及值得引用:
变量 | 意义 |
---|---|
# | 传递给shell脚本或函数的参数总数 |
* | 一次表示所有的命令行参数,置于双引号内,则展开为一单独参数 |
@ | 一次表示所有的命令行参数,置于双引号内,会展开为个别的参数 |
例:
$ set -- hello "hi there" greetings #调用set命令但不给任何选项,则设置位置参数的值
$ echo $#
3
$ for i in $*; do echo i is $i; done
i is hello
i is hi # 带空格的字符串展开为多个单词
i is there
i is greetings
$ for i in $@; do echo i is $i; done # 不加双引号,$*与$@效果相同
i is hello
i is hi
i is there
i is greetings
$ for i in "$*"; do echo i is $i; done #加了双引号,$*表示一个字符串
i is hello hi there greetings #等同于 "$1 $2 ..."
$ for i in "$@"; do echo i is $i ; done #加了双引号,$@保留真正的参数
i is hello #等同于 "$1" "$2" ...
i is hi there
i is greetings
shift
命令用于”截去“来自列表的位置参数,由左开始。一旦执行shift,$1
的初始值
永远消失,取而代之的是$2
的旧值。$2
的值变为$3
的旧值,依次类推。同时,$#
值
减1.
一个常见用法是对参数选项进行处理:
while [ $# != 0 ]
do
case $1 in
... #处理第一个参数
esac
shift #移除第一个参数
done
特殊变量(内置变量)
除了上面介绍的特殊变量,脚本还内置了如下变量(不完全列出):
变量 | 意义 |
---|---|
? | 前一命令的退出状态 |
$ | shell进程的进程ID,常用于建立唯一性的临时文件名 |
HOME | 根(登录)目录 |
IFS | 内部字符分隔符,一般设为空格、制表符tab及换行newline |
LANG | 当前locale的默认名称 |
PATH | 命令的查找路径 |
PWD | 当前工作目录 ! |
小结
参数展开是引用变量值的过程。除了两种普通的引用变量本身值的方法:$var
和${var}
,
对变量还可以使用替换运算符和模式匹配运算符,对变量进行处理得到想要的值。shell内置
了许多变量可以方便调用脚本环境。
熟练掌握参数展开语法,可以方便的处理字符串,包括文件名路径提取、后缀名修改,提取子字符串等等操作。

