Shell编程学习笔记:变量篇(二)

| Comments

参数展开

参数展开(parameter expansion)是shell提供变量值在脚本程序中使用的过程。 缺省情况,未定义的变量会展开成null(空的)字符串。

有两种方式引用变量值:

  • $var
  • ${var}

注:不要和命令替换操作$()搞混。

展开运算符

分为替换运算符模式匹配运算符

  • 替换运算符

替换运算符用于测试变量是否存在,且在某种情况下允许默认值(缺省值)的替换。比如, 当脚本需要根据用户输入位置参数来决定脚本执行行为时,为了防止用户执行时忘了在 命令行上输入参数导致脚本运行出错,可以使用替换运算符得到一个缺省值备用。

运算符 替换 用途
${varname:-value} 如果varname存在且非null,则返回其值;否则,返回value 如果变量未定义,返回默认值
${varname:=value} 如果varname存在且不是null,则返回他的值;否则,设置它为value,并返回其值 如果变量未定义,则设置变量为默认值
${varname:?message} 如果varname存在且非null,则返回它的值;否则,显示varname:message,并退出当前的命令或脚本 为了捕捉由于变量未定义所导致的错误
${varname:+value} 如果varname存在且非null,则返回value;否则,返回null 测试变量的存在

注1:以上每个运算符内冒号(:)都是可选的,如果省略冒号,则将每个定义中的“存在且非null”部分改为 “存在”,即运算符仅用于测试变量是否存在,不测试其是否有值。

注2:varname前不需要加$符号。

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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}   # 0
  • 模式匹配运算符

通常用来分割路径的组成部分,例如目录前缀、文件名后缀等。

运算符 替换 用途
${variable#pattern} 如果模式匹配变量值开头处,则删除匹配的最短部分,并返回剩下的部分
${variable##pattern} 如果模式匹配变量值的开头处,则删除匹配的最长部分,并返回剩下的部分 保留basename
${variable%pattern} 如果模式匹配变量值的结尾处,则删除匹配的最短部分,并返回剩下的部分 去除后缀
${variable%%pattern} 如果模式匹配变量值得结尾处,则删除匹配的最长部分,并返回剩下的部分

注:

  • #匹配前面,%匹配后面;单个#%匹配最短部分,两个匹配最长部分(贪婪算法)。
  • 模式/*/匹配任何位于两个斜杠之间的元素,.*匹配点号后面接着的任何元素。

例:

1
2
3
4
5
path=/home/tolstoy/mem/long.file.name
echo ${path#/*/}        # tolstoy/mem/long.file.name
echo ${path##/*/}     # long.file.name
echo ${path%.*}         # /home/tolstoy/mem/long.file 
echo ${path%%.*}      # /home/tolstoy/mem/long

${#variable}返回$variable值里的字符长度。

位置参数

位置参数(positional parameter)指shell脚本的命令行参数,也表示shell函数内的函数参数。 名称以单个整数命名。$0指脚本名称,$1是第一个参数,依次类推。当参数大于9个时,引用 该参数时需要用{}括起来。

值测试与模式替换运算符结合使用:

1
filename=${1:-/dev/tty}

使用内部变量对传递的参数个数及值得引用:

变量 意义
# 传递给shell脚本或函数的参数总数
* 一次表示所有的命令行参数,置于双引号内,则展开为一单独参数
@ 一次表示所有的命令行参数,置于双引号内,会展开为个别的参数

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ 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.

一个常见用法是对参数选项进行处理:

1
2
3
4
5
6
7
while [ $# != 0 ]
do
    case $1 in
    ...                   #处理第一个参数
    esac
    shift               #移除第一个参数
done

特殊变量(内置变量)

除了上面介绍的特殊变量,脚本还内置了如下变量(不完全列出):

变量 意义
? 前一命令的退出状态
$ shell进程的进程ID,常用于建立唯一性的临时文件名
HOME 根(登录)目录
IFS 内部字符分隔符,一般设为空格、制表符tab及换行newline
LANG 当前locale的默认名称
PATH 命令的查找路径
PWD 当前工作目录

小结

参数展开是引用变量值的过程。除了两种普通的引用变量本身值的方法:$var${var}, 对变量还可以使用替换运算符和模式匹配运算符,对变量进行处理得到想要的值。shell内置 了许多变量可以方便调用脚本环境。

Comments