bash之参数扩展(Parameter Expansion)

写在前面

如果你问我bash的这么多扩展哪个功能最强大,那我会毫不犹豫地告诉你,当然是参数扩展啦~

为什么说参数扩展功能强大呢?那是因为通过参数扩展功能,我们可以完成很多意想不到的功能,例如可以完成参数值的删除、截取以及替换等功能~

 

SHELL参数以及参数的分类

开始讲述参数扩展之前,我们先要了解什么是shell的参数,以及引用参数的不同方法。

其实在shell编程中,参数(parameter)是个大概念,也是个笼统的概念,在bash手册中对参数的定义只是一句话:

A parameter is an entity that stores values. 

意思是说在shell中参数是个实体(entity),这个实体中存储着各式各样的值(values)。

紧接着提到:

It can be a name, a number, or one of the special characters listed below under Special Parameters.

这句话其实是告诉我们,可以通过三类方式来引用参数,从而得到参数中存储的值。根据引用方式的不同,可以将参数分为三类,归纳如下:

(1)通过名称(name)来引用参数,这样的参数我们称之为变量(variables )。一个变量拥有自己的值和诸多属性,属性可以通过declare来设定,可以通过unset来取消一个变量。

(2)通过数字(number)来引用参数,这样的参数我们称之为位置参数(Positional Parameters)。位置参数在脚本被调用时自动初始化为传递给脚本的参数。脚本中调用函数时,位置参数会暂时替换成传递给函数的参数。我们可以使用set命令来改变位置参数的值,但是不能试图通过赋值语句来改变位置参数的值。(参考《Handling positional parameters》)

(3)最后还有一类参数,被称之为特殊参数(Special Parameters)。特殊在哪里? 特殊在我们只能通过shell内部预定义的特殊符号来引用它们,并且我们只能引用,不能试图通过赋值语句来重新赋值。预定义的特殊符号包括:*  @  $  ?  !  -  $  0  (参考《Special parameters and shell variables》)

(参考链接:《Parameter》《Parameters》)

 

什么是参数扩展呢?

讲白了,所谓参数扩展就是通过符号$获得参数中存储的值。只不过呢,在获得最终的结果之前,允许我们对参数以及参数值做很多操作,例如本文一开始就提到的对参数值进行删除、截取以及替换等操作~

本篇博文就是详细讨论参数扩展过程中我们可以进行的诸多操作。

 

最简单的形式

参数扩展最简单直接的形式如下:

$parameter

或者

${parameter}

个人倾向于后者,第一有花括号一看就知道是参数扩展,其次可以根据需要在右花括号后头追加字符(串),否则shell会认为是参数的一部分。举个小例子就知道了,如下:

[09:49:23@astrol:~]$ WORD=car
[09:49:25@astrol:~]$ echo "The plural of $WORD is most likely $WORDs"
The plural of car is most likely
[09:49:27@astrol:~]$ echo "The plural of $WORD is most likely ${WORD}s"
The plural of car is most likely cars

可以看到不加花括号的话,shell认为WORDs是参数,然而我们并没有设置过这个参数,因此扩展结果为空。

需要注意的是,在bash中引用位置参数时,大于第9个参数时,两位的数字要求必须要在花括号内。例如:${10}

另外,后文介绍的各种操作都是需要在花括号内进行的。

 

使用默认值(Use Default Values)

test

 

赋值默认值(Assign Default Values)

test

 

间接扩展(indirect expansion)

间接扩展也被很多人称为间接引用。如果熟悉C/C++的话,可以简单的把间接扩展理解成指针变量。

 

 

 

子串扩展(Substring Expansion)

${parameter:offset}

${parameter:offset:length}

子串扩展的意思是从offset位置开始截取长度为length的子串,如果没有提供length,则是从offset开始到结尾。需要注意的几点是:

(1)如果offset是个负值,开始位置是从字符串末尾开始算起,然后取长度为length的子串。例如,-1代表是从最后一个字符开始。

(2)如果length是个负值,那么length的含义不再代表字符串长度,而是代表另一个offset,位置从字符串末尾开始,扩展的结果是offset ~ length之间的子串。

(3)如果parameter是@,也就是所有的位置参数时,offset必须从1开始。

来看几个例子:

[17:58:36@astrol:~]$ MYSTRING="Be liberal in what you accept, and conservative in what you send"
[17:59:19@astrol:~]$ echo ${MYSTRING}
Be liberal in what you accept, and conservative in what you send
[17:59:30@astrol:~]$ echo ${MYSTRING:34}
conservative in what you send
[17:59:42@astrol:~]$ echo ${MYSTRING:34:13}
conservative
[17:59:56@astrol:~]$ echo ${MYSTRING: -10:5}
t you
[18:00:18@astrol:~]$ echo ${MYSTRING:(-10):5}
t you
[18:00:23@astrol:~]$ echo ${MYSTRING:11:-17}
in what you accept, and conservative

可以看到当offset是负值时,负号(-)必须与冒号(:)有间隔,这是为了避免与上文提到的${parameter:-word} 混淆。

 

查找和替换(Pattern  substitution)

${parameter/pattern/string}

${parameter//pattern/string}

${parameter/pattern}

${parameter//pattern}

pattern和路径扩展(pathname expansion)中的模式匹配(pattern matching)一样(详情可参考文章《bash之通配符》),匹配后的子串会用string替换掉。需要注意的有以下几点:

(1)parameter之后如果是/,则只替换匹配到的第一个子串;parameter之后如果是//,则替换所有匹配到的子串。

(2)当string为空时,则相当于将匹配的子串删除。

(3)特殊符号#%在这种情况下分别锚定(Anchoring )字符串的开始和结尾。

(4)如果bash的nocasematch选项参数是打开的(shopt -s nocasematch),则匹配的过程大小写是不敏感的。

例子如下:

[19:26:39@astrol:~]$ MYSTRING="Be liberal in what you accept, and conservative in what you send"
[19:26:40@astrol:~]$ echo ${MYSTRING}
Be liberal in what you accept, and conservative in what you send
[19:26:46@astrol:~]$ echo ${MYSTRING//conservative/happy}
Be liberal in what you accept, and happy in what you send
[19:27:04@astrol:~]$ echo ${MYSTRING/in/by}
Be liberal by what you accept, and conservative in what you send
[19:27:21@astrol:~]$ echo ${MYSTRING//in/by}
Be liberal by what you accept, and conservative by what you send
[19:27:24@astrol:~]$ echo ${MYSTRING/conservative/}
Be liberal in what you accept, and in what you send
[19:27:50@astrol:~]$ MYSTRING=xxxxxxxxxxxxxxx
[19:28:09@astrol:~]$ echo ${MYSTRING}
xxxxxxxxxxxxxxx
[19:28:17@astrol:~]$ echo ${MYSTRING/#x/y}
yxxxxxxxxxxxxxx
[19:28:26@astrol:~]$ echo ${MYSTRING/%x/y}
xxxxxxxxxxxxxxy

bash的这个查找替换功能跟sed的很像,不同的是这里的pattern不是正则表达式。

 

查找并删除(Remove matching prefix/suffix pattern)

${parameter#pattern}

${parameter##pattern}

${parameter%pattern}

${parameter%%pattern}

删除匹配到的子串。直接来看例子吧,假设我们定义了一个变量为:

file=/dir1/dir2/dir3/my.file.txt

那么:

${file#*/}:删除第一个 / 及其左边的字符串:dir1/dir2/dir3/my.file.txt 
${file##*/}:删除最后一个 / 及其左边的字符串:my.file.txt , 相当于basename ${file}
${file#*.}:删除第一个 . 及其左边的字符串:file.txt 
${file##*.}:删除最后一个 . 及其左边的字符串:txt  
${file%/*}:删除最后一个 / 及其右边的字符串:/dir1/dir2/dir3,相当于dirname ${file}
${file%%/*}:删除第一个 / 及其右边的字符串:(空值) 
${file%.*}:删除最后一个 . 及其右边的字符串:/dir1/dir2/dir3/my.file 
${file%%.*}:删除第一个 . 及其右边的字符串:/dir1/dir2/dir3/my

记忆的方法为:
# 是去掉左边(在键盘上 # 在 $ 之左边) 
% 是去掉右边(在键盘上 % 在 $ 之右边) 
单一符号是最小匹配﹔两个符号是最大匹配。

 

获取参数值长度(Parameter  length)

${#parameter}

这个扩展很简单,就是返回parameter值的长度值。

[20:49:27@astrol:~]$ MYSTRING="Be liberal in what you accept, and conservative in what you send"
[20:49:27@astrol:~]$ echo ${MYSTRING}
Be liberal in what you accept, and conservative in what you send
[20:49:34@astrol:~]$ echo ${#MYSTRING}
64

 

大小写转换(Case modification)

${parameter^}

${parameter^^}

${parameter,}

${parameter,,}

字符^意思是将第一个字符转换成大写字母,^^的意思是将所有的字符转换成大写字母。

字符,意思是将第一个字符转换成小写字母,,,的意思是将所有的字符转换成小写字母。

来看如下例子:

[20:00:49@astrol:~]$ lower="lowercase letters"
[20:00:55@astrol:~]$ echo ${lower}
lowercase letters
[20:01:08@astrol:~]$ echo ${lower^}
Lowercase letters
[20:01:12@astrol:~]$ echo ${lower^^}
LOWERCASE LETTERS
[20:01:15@astrol:~]$ echo ${lower} | tr '[:lower:]' '[:upper:]'
LOWERCASE LETTERS
[20:01:43@astrol:~]$
[20:01:49@astrol:~]$ UPPER="UPPER LETTERS"
[20:02:01@astrol:~]$ echo ${UPPER}
UPPER LETTERS
[20:02:07@astrol:~]$ echo ${UPPER,}
uPPER LETTERS
[20:02:09@astrol:~]$ echo ${UPPER,,}
upper letters
[20:02:11@astrol:~]$ echo ${UPPER} | tr '[:upper:]' '[:lower:]'
upper letters

关于大小写转换的更多例子可以参考《Shell Script: Convert Lowercase to Uppercase

 

参考链接:

 

BASH: Parameter expansion》(需梯子)

shell变量详解

Linux 技巧: Bash 参数和参数扩展》《Bash parameters and parameter expansions

Shell参数扩展

Linux Shell参数扩展(Parameter Expansion)

Bash parameters and parameter expansions

An introduction to parameter expansion in Bash

第三十五章 : 字符串和数字》(shell百科

Bash String Processing

How-To: Bash Parameter Expansion and Default Values

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值