当前位置: 首页 > news >正文

shell脚本变量详解

什么是变量

        顾名思义,变量就是程序设计语言中的一个可以变化的量,当然,可以变化的是变量的值。几乎所有的程序设计语言都有定义变量,并且其涵义也大同小异。从本质上讲,变量就是在程序中保存用户数据的一块内存空间,而变量名就是这块内存空间的地址。在程序的执行过程中,保存数据的内存空间的内容可能会不断地发生变化,但是,代表内存地址的变量名却保持不变。

变量命名

        在Shell中,变量名可以由字母、数字或者下划线组成,并且只能以字母或者下划线开头。对于变量名的长度,Shell没有做出明确的规定。因此,用户可以使用任意长度的字符串来作为变量名。但是,为了提高程序的可读性,建议用户使用相对较短的字符串作为变量名。在一个设计良好的程序中,变量的命名有着非常大的学问。通常情况下,用户应该尽可能选择有明确意义的英文单词作为变量名,尽量避免使用拼音或者毫无意义的字符串作为变量名。这样的话,用户通过变量名就可以了解该变量的作用。

变量的类型

根据数据类型分类

        Shell是一种动态类型语言和弱类型语言,即在Shell中,变量的数据类型毋需显示地声明,变量的数据类型会根据不同的操作有所变化。准确地讲,Shell中的变量是不分数据类型的,统一地按照字符串存储。但是根据变量的上下文环境,允许程序执行一些不同的操作,例如字符串的比较和整数的加减等等。
什么是弱类型语言、强类型语言?
强类型和弱类型主要是站在变量类型处理的角度进行分类的。强类型是指不允许隐式变量类型转
换,弱类型则允许隐式类型转换。
强类型语言,当你定义一个变量是某个类型,如果不经过代码显式转换(强制转化)过,它
就永远都是这个类型,如果把它当做其他类型来用,就会报错。
弱类型语言,你想把这个变量当做什么类型来用,就当做什么类型来用,语言的解析器会自
动(隐式)转换。
比如:
C语言定义变量,int+变量名,实则前面的int就是给变量内存划分了等级,int定义整型所以
空间里只能存放整型,这就是强类型。php、C#和Python等都是强类型语言。
declare 命令参数详解
参数功能描述示例
-指定变量的属性(如 -i-r-a-x)。declare -i COUNT=10(定义整数变量)
+取消变量的属性(与 - 相反)。declare +x VAR(取消环境变量属性)
-p显示变量的属性和值(若未指定变量名,则显示所有变量)。declare -p PATH(显示 PATH 变量的属性和值)
-i将变量定义为整数类型,支持算术表达式。计算失败时返回 0。declare -i A=5+3; echo $A(输出 8)
-r将变量声明为只读(等同于 readonly),不可修改或删除。declare -r PI=3.14; PI=3(报错:只读变量不可修改)
-a将变量声明为数组(默认支持,无需显式声明)。declare -a FRUITS=("apple" "banana"); echo ${FRUITS[1]}(输出 banana)
-f显示所有自定义函数的名称和函数体(若指定函数名,则只显示该函数)。declare -f(显示所有函数)
-x将变量设置为环境变量(等同于 export),使其在子进程中可用。declare -x DB_HOST=localhost(设置环境变量)

部分代码示例:

#声明整数型变量
[root@kittod ~]# declare -i ab
[root@kittod ~]# ab=33
[root@kittod ~]# echo $ab
33
#改变变量属性
[root@kittod ~]# declare -i ef
[root@kittod ~]# ef=1
[root@kittod ~]# echo $ef
1
[root@kittod ~]# ef="wer"
[root@kittod ~]# echo $ef
0
[root@kittod ~]# declare +i ef
[root@kittod ~]# ef="wer"
[root@kittod ~]# echo $ef
wer
#设置变量只读
[root@kittod ~]# declare -r ab
[root@kittod ~]# ab=22
-bash: ab: readonly variable
[root@kittod ~]# echo $ab
33
#声明数组变量
[root@kittod ~]# declare -a cd='([0]="a" [1]="b" [2]="c")'
[root@kittod ~]# echo ${cd[1]}
b
[root@kittod ~]# echo ${cd[@]}
a b c

 根据作用域分类

根据作用域可将变量分为环境变量(全局变量)和普通变量(局部变量)
1、环境变量


        环境变量也可称为全局变量,可以在创建它们的shell及其派生出来的任意子进程shell中使用(su - 切换用户会读取新的环境变量),环境变量又可分为自定义环境变量和bash内置的环境变量。

(1)自定义环境变量


一般是指用export(shell脚本基础中详细解释)内置命令导出的变量,用于定义shell的运行环境,保证shell命令的正确执行。环境变量可以在命令行中设置和创建,但用户退出命令行时这些变量值就会丢失,即该环境变量只在当前shell和子shell中有效。如果希望永久保存环境变量,可以在配置文件中设置。
①用户的环境变量配置(non-login shell)
/.bash_profile或/.bashrc
②全局环境变量的配置(login shell)
/etc/bashrc、/etc/profile文件或者/etc/profile.d目录中定义。
注意:按照系统规范,所有环境变量的名字均采用大写形式。在将环境变量应用于用户进程程序之前,都应该用命令export导出。有一些环境变量,比如HOME,PATH,SHELL,UID,USER等,在用户登录前就已经被/bin/login程序设置好了,通常环境变量被定义并保存在用户家目录下的.bash_profile文件或全局的配置文件/etc/profile中。


(2)bash内置的环境变量


shell内置的环境变量是所有的shell程序都可以使用的变量。shell程序在运行时,都会接收一组变量来确定登录用户名、命令路径、终端类型、登录目录等,这组变量就是环境变量。环境变量会影响到所有的脚本的执行结果。

以下是一些常见的 Bash 内置环境变量:

变量名描述
HOME用户的主目录路径。
PATH用于指定命令的搜索路径,多个路径之间用冒号(:)分隔。
PWD当前工作目录的绝对路径。
OLDPWD上一个工作目录的绝对路径。
USER当前登录的用户名。
UID当前用户的 ID 号。
SHELL用户当前使用的 shell 程序的路径。
TERM终端类型,用于确定终端的功能和特性,常见的值有 xtermvt100 等。
LANG系统的语言环境设置,影响字符编码、排序规则等。
LC_ALL用于覆盖 LANG 变量,设置整个本地化环境。
PS1命令行提示符的设置字符串,用于定义命令行的显示格式。
PS2当命令未结束,需要继续输入时显示的提示符,默认为 >
IFS内部字段分隔符,用于分割命令输出或变量值的字符串,默认为空格、制表符和换行符。
BASH_VERSION当前 Bash shell 的版本号。
HISTSIZE历史命令记录的最大数量。
HISTFILESIZE历史命令文件的最大大小。

注:可使用env查看环境变量 

局部变量
普通变量也可称为局部变量,与全局变量相比,局部变量的使用范围较小,通常仅限于某
个程序段访问,例如函数内部。在Shell语言中,可以在函数内部通过local关键字定义局部变
量,另外,函数的参数也是局部变量。
函数中区别(代码示例)
[root@kittod ~]# vim vartest.sh
#!/bin/bash
#定义函数
func()
{
#输出全局变量v1的值
echo "global variable v1 is $v1"
#定义局部变量v1
local v1=2
#输出局部变量v1的值
echo "local variable v1 is $v1"
}
#定义全局变量v1
v1=1
#调用函数
func
#输出全局变量v1的值
echo "global variable v1 is $v1"
[root@kittod ~]# chmod a+x vartest.sh
[root@kittod ~]# ./vartest.sh
global var v1 is 1
local var v1 is 2
global var v1 is 1

变量的定义

        在Shell中,通常情况下用户可以直接使用变量,而毋需先进行定义,当用户第一次使用某个变量名时,实际上就同时定义了这个变量,在变量的作用域内,用户都可以使用该变量。

1、变量定义示例:变量名=变量值

#定义变量a
a=1
#定义变量b
b="hello"
#定义变量c
c="hello world"
#定义备份路径
bak_dir=/data/backup
#把一个命令的结果赋值变量
变量名=`ls`
变量名=$(ls)
注意:
(1)“=”前后不能有空格
[root@localhost ~]# a= 3
-bash: 3: 未找到命令
[root@localhost ~]# b =4
-bash: b: 未找到命令
(2)字符串类型建议用引号括起来,尤其是特殊字符或有空格
stu_name="zhang san"
引用变量: {变量名}
查看变量:echo $变量名,set(可查看所有变量:包括自定义变量和环境变量),env显示全局
变量,declare输出所有的变量、函数、整数和已经导出的变量。
取消变量:unset 变量名
作用范围:仅在当前shell中有效
注:可使用export指令将变量转换成环境变量

2、位置参数和预定义变量

        许多情况下,Shell脚本都需要接收用户的输入,根据用户输入的参数来执行不同的操作。从命令行传递给Shell脚本的参数又称为位置参数,Shell脚本会根据参数的位置使用不同的位置
参数变量读取它们的值。

以下是一些常见的 Bash 预定义变量:

变量名描述
$0当前脚本或命令的名称。
$1 - $9脚本或函数的位置参数,$1 是第一个参数,$2 是第二个参数,以此类推。
$#传递给脚本或函数的参数数量。
$@表示所有的位置参数,是一个包含所有参数的列表,在引用时会将每个参数作为独立的字符串处理。
$*与 $@ 类似,但它将所有参数作为一个字符串处理,参数之间用 IFS 的第一个字符分隔。
$$当前进程的 PID(进程 ID)。
$?上一个命令或函数的退出状态码,0 表示成功,非 0 表示失败。
$-当前 shell 的选项标志,是一个包含当前 shell 启用的选项的字符串。
$!最后一个在后台运行的进程的 PID。

shell中的引用(部分特殊符号) 

在bash中有很多特殊字符,这些特殊字符就具有特殊含义。引用就是通知shell将这些特殊字符当
作普通字符来处理。
  说明:反引号中的字符串将被解释为shell命令
[root@kittod ~]# echo "current user is: $USER"
current user is: root
[root@kittod ~]# echo 'current user is: $USER'
current user is: $USER
[root@kittod ~]# echo "current user is: `whoami`"
current user is: root
[root@kittod ~]# echo 'current user is: `whoami`'
current user is: `whoami`

变量的运算

Shell 和其他编程语言一样,支持多种运算符,包括:
算数运算符
关系运算符
布尔运算符
字符串运算符
文件测试运算符
原生bash不支持简单的数学运算,但是可以通过其他命令来实现,例如 awk 和 expr,expr 最常用。
expr 是一款表达式计算工具,使用它能完成表达式的求值操作。
两点注意:
1. 表达式和运算符之间要有空格,例如 2+2 是不对的,必须写成 2 + 2,这与我们熟悉的大多
数编程语言不一样。
2. 脚本中可能需要用到 `,注意这个字符不是常用的单引号,在 Esc 键下边。
为了能够正确处理Shell程序运行过程中遇到的各种情况,Linux Shell提供了一组测试运算符。通
过这些运算符,Shell程序能够判断某种或者几个条件是否成立。条件测试在各种流程控制语句, 例如判断语句和循环语句中发挥了重要的作用,所以,了解和掌握这些条件测试是非常重要的。

 expr命令的基本语法及其现代替代方式

expr用于计算表达式的值,语法为:

expr 表达式
 

例如:

expr 2 + 3    # 输出5
expr 5 \* 2   # 注意:乘号需要转义为\*
反引号(`)的作用

反引号用于命令替换,即将命令的输出结果替换到当前位置。
例如,若要将expr的计算结果赋值给变量,需用反引号包裹expr命令:

 
result=`expr 2 + 3`
echo $result  # 输出5
 

等价于更现代的$()语法:

 
result=$(expr 2 + 3)
echo $result  # 输出5
常见错误示例

错误写法

 
# 错误1:用反引号包裹表达式内部
result=expr `2 + 3`  # 错误!Bash会尝试执行"2 + 3"命令# 错误2:未正确转义特殊字符
result=$(expr 2 * 3)  # 错误!*会被解释为通配符
 

正确写法

 
result=$(expr 2 \* 3)  # 正确:用\*转义乘号
推荐替代方案

expr语法繁琐(需转义运算符),现代 Bash 推荐使用$(( ))进行算术扩展:

 
result=$((2 + 3))     # 无需转义,更简洁
result=$((2 * 3))     # 正确:乘号无需转义
echo $((result / 2))  # 直接计算并输出
总结表格
需求正确语法示例说明
直接计算并打印结果expr 2 + 3输出 5
将结果赋值给变量result=$(expr 2 + 3)使用$()或反引号包裹整个expr命令
复杂表达式计算result=$((2 + 3 * 4))推荐$(( ))语法,无需转义运算符
关键区别
语法用途示例
expr ...计算表达式的值expr 5 - 2 → 3
`expr ...`获取expr的结果并替换到命令中echo $(expr 5 - 2) → "3"
$(( ... ))算术扩展,更强大的表达式计算echo $((5 - 2)) → "3"
 

合理使用这些语法可以避免不必要的错误,提高脚本的可读性和效率。

基本测试语法

 算数运算符

运算符描述示例
+加法expr 5 + 3 结果为 8
-减法expr 5 - 3 结果为 2
*乘法expr 5 \* 3 结果为 15(注意在 Bash 中乘法运算符需要转义,(())无需转义
/除法expr 5 / 3 结果为 1(整数除法,结果取整)
%取模(取余数)expr 5 % 3 结果为 2
++自增a=5; ((a++)) 后,a 的值变为 6
--自减a=5; ((a--)) 后,a 的值变为 4

在 Bash 中,也可以使用 (( )) 来进行更简洁的算数运算,例如 ((a = 5 + 3)),这种方式不需要使用 expr 命令,并且支持更多的算数运算特性。同时,还可以使用 let 命令来进行算数运算,如 let a=5+3,效果与 (( )) 类似。

赋值运算符

运算符等价形式示例 (a=5)结果
=直接赋值a=10a=10
+=加后赋值((a += 3))a=8
-=减后赋值((a -= 3))a=2
*=乘后赋值((a *= 3))a=15
/=除后赋值((a /= 3))a=1
%=取模后赋值((a %= 3))a=2

 比较运算符

数值比较
运算符描述示例 (a=5; b=3)结果
-eq等于[ $a -eq $b ] && echo truefalse
-ne不等于[ $a -ne $b ] && echo truetrue
-gt大于[ $a -gt $b ] && echo truetrue
-lt小于[ $a -lt $b ] && echo truefalse
-ge大于等于[ $a -ge $b ] && echo truetrue
-le小于等于[ $a -le $b ] && echo truefalse
(()):
[root@kittod ~]# (( 2!=3 ));echo $?
0
[root@kittod ~]# ((2!=3));echo $?
0
[root@kittod ~]# ((2=3));echo $?
-bash: ((: 2=3: attempted assignment to non-variable (error token is
"=3")
1
[root@kittod ~]# ((2==3));echo $?
1
[root@kittod ~]# ((2>3));echo $?
1
[root@kittod ~]# ((2<3));echo $?
0[[]]:
[root@kittod ~]# [[ 2 != 3 ]];echo $?
0
[root@kittod ~]# [[ 2 != 2 ]];echo $?
1
[root@kittod ~]# [[ 2!=2 ]];echo $? 未写空格,导致出错
0[]:
[root@kittod ~]# [ 2 -ne 3 ];echo $?
0
[root@kittod ~]# [ 2 -ne 2 ];echo $?
1test:
[root@kittod ~]# test 2 -eq 3;echo $?
1
[root@kittod ~]# test 2 -eq 2;echo $?
0

 

字符串比较
运算符描述示例 (str1="abc"; str2="def")结果
=等于[ "$str1" = "$str2" ]false
!=不等于[ "$str1" != "$str2" ]true
-z字符串为空[ -z "$str1" ]false
-n字符串非空[ -n "$str1" ]true
操作符功能描述示例返回值($?
-z检查字符串长度是否为 0(空字符串)[ -z "" ]0(成功)
-z检查变量是否为空str=""; [ -z "$str" ]0(成功)
-z检查命令输出是否为空output=$(ls /nonexistent); [ -z "$output" ]0(成功)

 

文件测试运算符 

结果都是true/false,两个表格存在重复。

操作符功能示例
-e文件或目录存在[ -e "path" ]
-f是普通文件[ -f "file.txt" ]
-d是目录[ -d "dir" ]
-r有读权限[ -r "file.txt" ]
-w有写权限[ -w "file.txt" ]
-x有执行权限[ -x "script.sh" ]
-s文件大小不为 0[ -s "data.log" ]
-O用户拥有该文件[ -O "$HOME/file" ]
-N文件自上次读取后被修改[ -N "config.ini" ]
f1 -nt f2文件 f1 比 f2 新[ "new.txt" -nt "old.txt" ]
f1 -ot f2文件 f1 比 f2 旧[ "old.txt" -ot "new.txt" ]
运算符说明举例
-b file检测文件是否是块设备文件,如果是,则返回 true。[ -b $file ]返回 false。
-c file检测文件是否是字符设备文件,如果是,则返回 true。[ -c $file ]返回 false。
-g file检测文件是否设置了 SGID 位,如果是,则返回 true。[ -g $file ]返回 false。
-k file检测文件是否设置了粘着位 (Sticky Bit),如果是,则返回 true。[ -k $file ]返回 false。
-p file检测文件是否是有名管道,如果是,则返回 true。[ -p $file ]返回 false。
-u file检测文件是否设置了 SUID 位,如果是,则返回 true。[ -u $file ]返回 false。
-s file检测文件是否为空(文件大小是否大于 0),不为空返回 true。[ -s $file ]返回 true。

 

其他检查符:
-S : 判断某文件是否 socket。
-L : 检测文件是否存在并且是一个符号链接。
测试文件的读、写、执行等属性,不光是根据文件属性rwx的标识来判断,还要看当前执行测试
的用户是否真的可以按照对应的权限操作文件。
测试代码示例:
test:
[root@kittod ~]# test -f file;echo $?
1
[root@kittod ~]# touch file
[root@kittod ~]# test -f file;echo $?
0
[root@kittod ~]# test -f file1;echo $?
1
[root@kittod ~]# test -x file;echo $?
1
[root@kittod ~]# ll
total 4
-rw-------. 1 root root 1263 Dec 16 19:11 anaconda-ks.cfg
-rw-r--r--. 1 root root 0 Apr 25 22:14 file
[root@kittod ~]# chmod +x file
[root@kittod ~]# test -x file;echo $?
0[]:
[root@kittod ~]# [ -f file ];echo $?
0
[root@kittod ~]# [ -f file1 ];echo $?
1
[root@kittod ~]# [ -w file1 ];echo $?
1
[root@kittod ~]# ll
total 4
-rw-------. 1 root root 1263 Dec 16 19:11 anaconda-ks.cfg
-rwxr-xr-x. 1 root root 0 Apr 25 22:14 file
[root@kittod ~]# [ -w file ];echo $?
0[[]]:
[root@localhost test3]# ll
total 0
-rw-r--r--. 1 root root 0 Feb 20 10:35 file
[root@localhost test3]# [[ -f file ]];echo $?
0
[root@localhost test3]# [[ -f file1 ]];echo $?
1
[root@localhost test3]# [[ -x file1 ]];echo $?
1路径用变量来代替
注意:如果测试的文件路径是用变量来代替,变量一定要加引号[root@localhost test3]# echo $filepath 该变量值为空
[root@localhost test3]# test -f $filepath;echo $?
0
[root@localhost test3]# test -f "$filepath";echo $?
1但是当变量不为空时正常:
[root@free etc]# echo $path
/etc
[root@free etc]# test -d $path;echo $?
0
练习:
(1)如果用户输入的文件为空时显示:you must input a filename,并中断程序;
(2)如果用户输入的文件不存在时,显示the file do not exist,并中断程序;
(3)如果文件存在,判断该文件的文件类型和执行者对该文件所拥有的权限。
说明:由于root在很多权限的限制上面都是无效的,所以使用root执行这个脚本时,常常会发现
与ls -l的结果不相同。所以建议使用一般用户来执行这个脚本。
read -p "input a filename:" filename
test -z $filename && echo "you must input a filename" && exit 0
test ! -e $filename && echo "the file $filename do not exist" && exit 0
test -f $filename && filetype="regulare file"
test -d $filename && filetype="directory"
test -r $filename && perm="readable"
test -w $filename && perm="$perm writable"
test -x $filename && perm="$perm executable"
echo "the $filename is a $filetype"
echo "and the permissons are: $perm"

布尔运算符,逻辑运算符

一、逻辑运算符(用于条件判断)

运算符描述语法示例说明
&&逻辑与(短路与)cmd1 && cmd2如果 cmd1 成功(返回 0),则执行 cmd2;否则跳过 cmd2
||逻辑或(短路或)cmd1 || cmd2
如果 cmd1 失败(返回非 0),则执行 cmd2;否则跳过 cmd2
!逻辑非! cmd反转 cmd 的退出状态(成功变失败,失败变成功)。

二、测试命令中的布尔组合

1. [ ] 语法(传统测试)
运算符描述语法示例说明
-a逻辑与[ condition1 -a condition2 ]同时满足两个条件时返回真。注意:在 [[ ]] 中无效,建议用 &&
-o逻辑或[ condition1 -o condition2 ]满足任一条件时返回真。注意:在 [[ ]] 中无效,建议用 ``。
!逻辑非[ ! condition ]条件不成立时返回真。
2. [[ ]] 语法(增强型测试)
运算符描述语法示例说明
&&逻辑与[[ condition1 && condition2 ]]更现代的写法,支持短路求值(前一个条件为假时不再执行后一个)。
||逻辑或[[ condition1 || condition2 ]]更现代的写法,支持短路求值(前一个条件为真时不再执行后一个)。
!逻辑非[[ ! condition ]]条件不成立时返回真。

代码示例:

[root@kittod ~]# cat luoji.sh
#!/bin/bash
a=10
b=20
if [[ $a -lt 100 && $b -gt 100 ]]
then
echo "返回 true"
else
echo "返回 false"
fi
if [[ $a -lt 100 || $b -gt 100 ]]
then
echo "返回 true"
else
echo "返回 false"
fi
[root@kittod ~]# bash luoji.sh
返回 false
返回 truetest:
[root@kittod ~]# ll
total 0
-rw-r--r--. 1 root root 0 Apr 26 15:42 ceshi
-rw-r--r--. 1 root root 0 Apr 26 15:42 file
[root@kittod ~]# test -f file && echo 1 || echo 0
1
[root@kittod ~]# test -f file1 && echo 1 || echo 0
0
[root@kittod ~]# ! test -f file;echo $?
1
注:命令1 && 命令2,如果命令1执行不成功,则命令2不执行。
命令3 || 命令4,如果命令3成功,不执行命令4;如果命令3不成功,则执行命令4[]:
[root@kittod ~]# [ -f ceshi && -f file ];echo $?
-bash: [: missing `]'
2
[root@kittod ~]# [ -f ceshi || -f file ];echo $?
-bash: [: missing `]'
-bash: -f: command not found
127
[root@kittod ~]# [ -f file ] && [ -f ceshi ];echo $?
0
[root@kittod ~]# [ -f file ] || [ -f ceshi ];echo $?
0
[root@kittod ~]# [ -f file ] || [ -d ceshi ];echo $?
0
[root@kittod ~]# [ -f file1 ] || [ -d ceshi ];echo $?
1[[]]:
[root@kittod ~]# touch file
[root@kittod ~]# touch ceshi
[root@kittod ~]# [[ -f file && -f ceshi ]];echo $?
0
[root@kittod ~]# [[ -f file || -f ceshi ]];echo $?
0
[root@kittod ~]# [[ -f file && -d ceshi ]];echo $?
1(()):
[root@kittod ~]# ((2>3&&3>4));echo $?
1
[root@kittod ~]# ((2<3&&3<4));echo $?
0

变量扩展表达式

变量扩展表达式汇总表
表达式说明示例 (parameter="hello_world.txt")结果
${parameter}返回变量的内容。${parameter}hello_world.txt
${#parameter}返回变量内容的长度(按字符)。${#parameter}15
${parameter:offset}从位置 offset 开始提取子串到结尾(位置从 0 开始)。${parameter:6}world.txt
${parameter:offset:length}从位置 offset 开始提取长度为 length 的子串。${parameter:6:5}world
${parameter#word}从开头删除最短匹配的 word 子串(贪心匹配)。${parameter#*.}txt
${parameter##word}从开头删除最长匹配的 word 子串(非贪心匹配)。${parameter##*.}txt
${parameter%word}从结尾删除最短匹配的 word 子串。${parameter%.*}hello_world
${parameter%%word}从结尾删除最长匹配的 word 子串。${parameter%%_*}hello
${parameter/pattern/string}使用 string 替换第一个匹配的 pattern${parameter/_/-}hello-world.txt
${parameter//pattern/string}使用 string 替换所有匹配的 pattern${parameter//_/-}hello-world.txt
${parameter/#pattern/string}仅替换开头匹配的 pattern${parameter/#hello/hi}hi_world.txt
${parameter/%pattern/string}仅替换结尾匹配的 pattern${parameter/%.txt/.md}hello_world.md
特殊情况说明
  1. 负偏移
    offset 为负数时,表示从字符串末尾倒数:

    ${parameter: -4}  # 从倒数第4个字符开始到结尾 → ".txt"
    
  2. 模式匹配规则

    • word 和 pattern 支持通配符(如 *?)。
    • # 和 % 用于删除匹配的内容,而 / 用于替换。
  3. 空变量处理

    var=""
    ${var:-default}  # 若var为空,返回default → "default"
    ${var:=default}  # 若var为空,设置var为default并返回 → "default"
    
常见应用场景
需求表达式示例说明
提取文件名扩展名${filename##*.}从开头删除最长匹配的 *.,剩下扩展名(如 txt)。
提取文件名(不含扩展名)${filename%.*}从结尾删除最短匹配的 .*,剩下文件名(如 hello_world)。
替换路径中的目录名${path//old/new}将路径中所有 old 替换为 new(如 /old/dir → /new/dir)。
截取子串${str:3:5}提取从位置 3 开始的 5 个字符(如 hello → llo)。
注意事项
  1. 空格敏感
    ${parameter: offset:length}(带空格)会导致错误,必须写成 ${parameter:offset:length}

  2. 模式与正则
    这些表达式使用的是通配符模式(如 * 匹配任意字符),而非正则表达式。若需正则,可使用 [[ $var =~ regex ]]

  3. 变量不存在
    若变量未定义,直接使用 ${var} 会报错,建议用 ${var:-default} 提供默认值。

通过这些变量扩展表达式,你可以在 Bash 中高效地处理字符串、路径和文件名,而无需依赖外部命令(如 sedawk)。

示例代码
截取字符串:
[root@localhost ~]# str1="hello world"
#返回变量长度
[root@localhost ~]# echo ${#str1}
11
#变量截取
#指定起始位置,一直到结束
[root@localhost ~]# echo ${str1:1}
ello world
#指定长度,不指定起始位置默认从开头开始
[root@localhost ~]# echo ${str1::3}
hel
#指定起始位置和长度
[root@localhost ~]# echo ${str1:1:3}
ell
#从右边第几个字符开始,及字符的个数
[root@localhost ~]# echo ${str1:0-1:1}
d
#输出右边的几个字符
[root@localhost ~]# echo ${str1:0-5}
world
[root@localhost ~]# echo ${str1: -5}
world
#提取完整字符串
[root@localhost ~]# echo ${str1:-5}
hello world删除字符串:
#获取后缀名tar.gz
[root@localhost ~]# filename=testfile.tar.gz
[root@localhost ~]# file=${filename#*.}
[root@localhost ~]# echo $file
tar.gz
#获取后缀名.gz
[root@localhost ~]# filename=testfile.tar.gz
[root@localhost ~]# file=${filename##*.}
[root@localhost ~]# echo $file
gz
#截取testfile.tar
[root@localhost ~]# filename=testfile.tar.gz
[root@localhost ~]# file=${filename%.*}
[root@localhost ~]# echo $file
testfile.tar
#截取testfile
[root@localhost ~]# filename=testfile.tar.gz
[root@localhost ~]# file=${filename%%.*}
[root@localhost ~]# echo $file
testfile

相关文章:

  • 【WebApi】YiFeiWebApi接口安装说明
  • python: union()函数用法
  • uniapp+vue3开发项目之引入vuex状态管理工具
  • 内存泄漏系列专题分析之十三:高通相机CamX内存泄漏内存占用分析--Camx pipeline的ION内存拆解方法
  • 从 Vue3 回望 Vue2:响应式的内核革命
  • 【bag of n-grams】 N-gram词袋模型 简介
  • 已情感分析入门学习大模型-初级篇
  • 进程与线程:09 进程同步与信号量
  • QLineEdit增加点击回显功能
  • Python 字典键 “三变一” 之谜
  • WebGIS 开发中的数据安全与隐私保护:急需掌握的要点
  • 带格式的可配置文案展示
  • 典籍指数问答模块回答格式修改
  • 深入浅出:C++数据处理类与计算机网络的巧妙类比
  • 嵌入式学习--江协51单片机day5
  • PostgreSQL 配置设置函数
  • SQL Server中delete table和truncate table删除全表数据哪个快?
  • 文件操作: File 类的用法和 InputStream, OutputStream 的用法
  • 基于SSM实现的健身房系统功能实现十六
  • 操作系统导论——第29章 基于锁的并发数据结构
  • 海运港口股掀涨停潮!回应关税下调利好,有货代称美线舱位爆了
  • 山东枣庄同一站点两名饿了么骑手先后猝死,当地热线:职能部门正调查
  • 4月国产新能源,降价潮迈入拐点
  • 不到1小时就能速发证件?央媒曝光健康证办理乱象
  • 白宫启动“返乡计划” ,鼓励非法移民自愿离开美国
  • 沃旭能源因成本上升放弃英国海上风电项目,或损失近40亿元