文章目录
1. 基本格式
Shell参数和变量扩展的最基本的格式是
${parameter}
如果parameter是数字,则是参数扩展;如果parameter是字符串,则是变量扩展;如果parameter是数组,遵循数组的扩展规则;parameter还可以是@, *, #, ?, -等,参考特殊参数的扩展。
只要在不引起混淆的情况下,{ }是可以省略的,比如
$ set -- a b c d e f g h i j k l m n
$ echo $12
a2
$ echo ${1}2
a2
$ echo ${12}
l
$ var=Hello
$ echo ${var}World
HelloWorld
$ echo $varWorld
在这种基础格式上,衍生出多种功能
2. ! 间接扩展
第一种情况,如果parameter不是nameref变量(参见declare内置命令)
$ var1=abc
$ var2=var1
$ echo ${var2}
var1
$ echo ${!var2}
abc
第二种情况,如果parameter是nameref变量
$ var1=abc
$ declare -n var2=var1
$ echo ${!var2}
var1
3. 条件扩展
条件扩展就是根据parameter是否存在,值是否是null来决定扩展出什么值。
3.1 缺省值扩展 -, :-
${parameter-word} # 如果parameter不存在,则扩展出的值为word,否则为parameter的值
${parameter:-word} # 如果parameter不存在,或者parameter存在但值为null,则扩展出的值为word,否则为parameter的值
$ echo ${unknown-abc}
abc
$ echo ${unknown:-abc}
abc
$ unknown=
$ echo ${unknown-abc}
$ echo ${unknown:-abc}
abc
$ echo ${unknown}
$ unknown=123
$ echo ${unknown-abc}
123
$ echo ${unknown:-abc}
123
3.2 赋值扩展 =, :=
${parameter=word} # 如果parameter不存在,则将word赋值给parameter
${parameter:=word} # 如果parameter不存在,或者parameter存在但值为null,则将word赋值给parameter
$ declare -p unknown
-bash: declare: unknown: not found
$ echo ${unknown=abc}
abc
$ echo ${unknown}
abc
$ unknown=
$ echo ${unknown}
$ echo ${unknown=abc}
$ echo ${unknown:=abc}
abc
$ echo ${unknown}
abc
$ unknown=123
$ echo ${unknown=abc}
123
$ echo ${unknown:=abc}
123
3.3 校验扩展 ?, :?
${parameter?word} # 如果parameter不存在,word被写到standard error里,并退出当前shell(非交互式shell)
${parameter:?word} # 如果parameter不存在,或者parameter存在但值为null,word被写到standard error里,并退出当前shell(非交互式shell)
$ cat script
echo ${1?'no parameter is given'};
$ bash script
script: line 1: 1: no parameter is given
$ echo $?
1
$ bash script 123
123
$ echo $?
0
3.4 替换扩展 +, :+
${parameter+word} # 如果parameter不存在,则什么都不会扩展,否则扩展为word
${parameter:+word} # 如果parameter不存在,或者parameter存在但值为null,则什么都不会扩展,否则扩展为word
$ echo ${unknown+word}
$ echo ${unknown:+word}
$ unknown=
$ echo ${unknown+word}
word
$ echo ${unknown:+word}
$ unknown=123
$ echo ${unknown+word}
word
$ echo ${unknown:+word}
word
3.5 条件扩展里的word
在条件扩展里,word不仅仅可以是简单的字符串,bash还会对word进行~扩展、参数和变量扩展、命令替换和算术扩展
$ echo ${unknown-~} # ~扩展
/home/felix
$ set -- a b c d
$ echo ${unknown-$1} # 参数扩展
a
$ foo=123
$ echo ${unknown-$foo} # 变量扩展
123
$ echo ${unknown-$(echo 'bar')} # 命令替换
bar
$ echo ${unknown-$(( 1+2 ))} # 算术扩展
3
4. 子串扩展
${parameter:offset}
${parameter:offset:length}
子串扩展的offset是从零索引开始的,位置参数扩展有点特殊,但是如果把$0考虑进去,offset也是从零索引开始。
4.1 字符串的子串扩展
从offset指定的字符开始,扩展出parameter值的length个字符。如果省略length,扩展到值的末尾。offset和length可以是整数,也可以是算术表达式。
如果offset小于零,则该值将用作距parameter值末尾的字符偏移量。注意,为了避免和:-混淆,附属的offset必须与冒号隔开至少一个空格。
如果length小于零,则也将其解释为距parameter值末尾的字符偏移量,而不是字符数,那么扩展出的结果是offset和length之间的字符。
$ string=01234567890abcdefgh
$ echo ${string:7}
7890abcdefgh
$ echo ${string:7:0}
$ echo ${string:7:2}
78
$ echo ${string:7:-2}
7890abcdef
$ echo ${string: -7}
bcdefgh
$ echo ${string: -7:0}
$ echo ${string: -7:2}
bc
$ echo ${string: -7:-2}
bcdef
$ set -- 01234567890abcdefgh
$ echo ${1:7}
7890abcdefgh
$ echo ${1:7:0}
$ echo ${1:7:2}
78
$ echo ${1:7:-2}
7890abcdef
$ echo ${1: -7}
bcdefgh
$ echo ${1: -7:0}
$ echo ${1: -7:2}
bc
$ echo ${1: -7:-2}
bcdef
$ array[0]=01234567890abcdefgh
$ echo ${array[0]:7}
7890abcdefgh
$ echo ${array[0]:7:0}
$ echo ${array[0]:7:2}
78
$ echo ${array[0]:7:-2}
7890abcdef
$ echo ${array[0]: -7}
bcdefgh
$ echo ${array[0]: -7:0}
$ echo ${array[0]: -7:2}
bc
$ echo ${array[0]: -7:-2}
bcdef
4.2 特殊参数$@的子串扩展
当parameter是@时,扩展结果是从offset开始的length个位置参数。
负数的offset是相对于最末尾位置参数的偏移量,-1的offset表示最后一个位置参数。
在这里,负数的length是错误的。
$ set -- 1 2 3 4 5 6 7 8 9 0 a b c d e f g h
$ echo ${@:7}
7 8 9 0 a b c d e f g h
$ echo ${@:7:0}
$ echo ${@:7:2}
7 8
$ echo ${@:7:-2}
bash: -2: substring expression < 0
$ echo ${@: -7:2}
b c
$ echo ${@:0}
./bash 1 2 3 4 5 6 7 8 9 0 a b c d e f g h
$ echo ${@:0:2}
./bash 1
$ echo ${@: -7:0}
4.3 索引数组的子串扩展
如果parameter是索引数组,且扩展形式是
${parameter[@]:offset:length}
${parameter[*]:offset:length}
结果是以${parameter[offset]}开头的length个数组成员。
负数的offset是相对于数组最大的索引值加1.
在这里,负数的length是错误的。
$ array=(0 1 2 3 4 5 6 7 8 9 0 a b c d e f g h)
$ echo ${array[@]:7}
7 8 9 0 a b c d e f g h
$ echo ${array[@]:7:2}
7 8
$ echo ${array[@]: -7:2}
b c
$ echo ${array[@]: -7:-2}
bash: -2: substring expression < 0
$ echo ${array[@]:0}
0 1 2 3 4 5 6 7 8 9 0 a b c d e f g h
$ echo ${array[@]:0:2}
0 1
$ echo ${array[@]: -7:0}
5. 变量名扩展
${!prefix*}
${!prefix@}
扩展为前缀为prefix的变量名称列表,以IFS的第一个字符分隔。 当使用@和双引号时,每个变量名都会扩展为一个单独的单词。
$ echo ${!P*}
PATH PIPESTATUS PPID PS1 PS2 PS4 PWD
6. 数组索引/键值扩展
${!name[@]}
${!name[*]}
如果name是一个索引数组,则扩展为name的索引列表。如果name是一个关联数组,则扩展为name的键值列表。如果name不是数组,则扩展为0。如果name不存在,则扩展为null. 当使用@和双引号时,每个索引或键值都会被扩展为一个单独的单词。
$ foo=(123 456 789)
$ echo ${!foo[@]}
0 1 2
$ bar=([a]=123 [b]=456 [c]=789 [d]=0)
$ echo ${!bar[@]}
d c b a
7. 获取变量值的长度、位置参数个数和数组的元素个数
${#parameter}
如果parameter是字符串变量或字符串参数,则结果为字符串的字符个数。
如果parameter是*或@,则结果为位置参数个数。
如果parameter是数组,且形式为name[@]或name[*],则结果为数组的元素个数。
$ var=0123456789
$ echo ${#var}
10
$ set -- 0 1 2 3 4 5 6 7 8 9 a b c d e f g
$ echo ${#@}
17
$ echo $#
17
$ foo=(123 456 789)
$ echo ${#foo}
3
$ echo ${#foo[@]}
3
8. 模式扩展
请提前了解模式匹配的规则。
开头模式删除扩展
${parameter#pattern}
${parameter##pattern}
如果pattern与parameter的扩展值的开头部分匹配,那么扩展的结果就是删除了匹配模式的parameter的值。#进行最短匹配,##进行最长匹配
$ var=123abc
$ echo ${var#1*}
23abc
$ echo ${var##1*}
结尾模式删除扩展
${parameter%pattern}
${parameter%%pattern}
如果pattern与parameter的扩展值的结尾部分匹配,那么扩展的结果就是删除了匹配模式的parameter的值。%进行最短匹配,%%进行最长匹配。
替换扩展
${parameter/pattern/string}
扩展parameter,并将扩展值与pattern的最长匹配项替换string. 如果pattern用 / 开头,则扩展值里的所有匹配项都替换为string,否则只替换第一个匹配的。
$ var=abab
$ echo ${var/a?/e}
eab
$ echo ${var//a?/e}
ee
如果pattern用#开头,则必须与扩展值的开头匹配。
如果pattern用%开头,则必须与扩展值的结尾匹配。
如果不提供string,或string为null,则扩展值里的匹配项就被删除。此时第二个 / 是可以省略的。
开启nocasematch选项时,模式匹配不考虑大小写。
改变字符的大小写
${parameter^pattern}
${parameter^^pattern}
${parameter,pattern}
${parameter,,pattern}
在这里,pattern只能匹配一个字符。扩展值中被匹配的字符会被更改大小写:^ 将第一个匹配的字符转换为大写;^^将所有匹配的字符转换为大写;, 将第一个匹配的字符转换为小写;,, 将所有匹配的字符转换为小写。如果pattern为 ?,将匹配所有字符。
以上扩展,如果parameter是特殊参数@和 * ,则扩展规则适用于每一个位置参数。如果parameter是数组array[@]和array[*]形式,则扩展规则适用于每一个数组成员。
转换操作符
${parameter@operator}
扩展结果是parameter值的转换或有关parameter本身的信息。operator可以是以下:
引号扩展Q
扩展结果是parameter值的引号形式,可用作输入。
$ var=abab
$ echo ${var@Q}
'abab'
ANSI-C转义扩张E
对parameter值里用 \ 转义的字符按照$'string’格式扩展。
$ var='\346\210\221\347\210\261\345\214\227\344\272\254\345\244\251\345\256\211\351\227\250'
$ echo ${var}
\346\210\221\347\210\261\345\214\227\344\272\254\345\244\251\345\256\211\351\227\250
$ echo ${var@E}
我爱北京天安门
提示符扩展P
按照提示字符串的转义规则扩展parameter.
$ bar='\u@\H:\W$'
$ echo ${bar@P}
felix@DESKTOP-GIGI:~$
声明扩展A
按照赋值语句或declare命令的格式扩展parameter
$ declare -i var=123
$ echo ${var@A}
declare -i var='123'
$ foo=(123, 456)
$ echo ${foo@A}
declare -a foo='123,
属性扩展a
扩展paramter的属性
$ foo=(123, 456)
$ echo ${foo@a}
a
$ declare -i var=123
$ echo ${var@a}
i
以上扩展,如果parameter是特殊参数@和 * ,则扩展规则适用于每一个位置参数。如果parameter是数组array[@]和array[*]形式,则扩展规则适用于每一个数组成员。