Shell基础——Shell参数和变量扩展

本文详细介绍了Shell的参数和变量扩展,包括基本格式、! 间接扩展、条件扩展(如缺省值、赋值、校验、替换)、子串扩展、变量名扩展、数组索引/键值扩展、获取变量长度及数组元素数量,以及模式扩展和转换操作符。通过这些扩展,Shell提供了强大的字符串处理和变量管理功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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[*]形式,则扩展规则适用于每一个数组成员。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值