shell脚本编程-进阶部分

接上一部分shell脚本编程基础

使用read命令来接受输入

使用read来把输入值分配给一个或多个shell变量,read从标准输入中读取值,给每个单词分配一个变 量,所有剩余单词都被分配给最后一个变量,如果变量名没有指定,默认标准输入的值赋值给系统内置 变量REPLY

read [options] [name ...]
#常见选项
-p   	#指定要显示的提示
-s 		#静默输入,一般用于密码
-n N 	#指定输入的字符长度N
-d 'CHAR'   #输入结束符
-t N 	#TIMEOUT为N秒

bash shell 的配置文件

bash shell的配置文件很多,可以分成下面类别

按生效范围划分两类

全局配置:针对所有用户皆有效

/etc/profile
/etc/profile.d/*.sh
/etc/bashrc ------------------------ /etc/bash.bashrc #ubuntu  

个人配置:只针对特定用户有效

~/.bash_profile
~/.bashrc

shell登录两种方式分类

交互式登录

  • 直接通过终端输入账号密码登录

  • 使用 su - UserName 切换的用户

配置文件生效和执行顺序:

#放在每个文件最前
/etc/profile
/etc/profile.d/*.sh
/etc/bashrc 
~/ .bash_ profile
~/ .bashrc
/etc/bashrc #此文件执行两次
#放在每个文件最后
/etc/profile.d/*.sh
/etc/bashrc
/etc/profile
/etc/bashrc   #此文件执行两次
~/.bashrc
~/.bash_profile

注意:文件之间的调用关系,写在同一个文件的不同位置,将影响文件的执行顺序

非交互式登录

  • su UserName

  • 图形界面下打开的终端

  • 执行脚本

  • 任何其它的bash实例

执行顺序:

/etc/profile.d/*.sh
/etc/bashrc
~/.bashrc

按功能划分分类

内容 Profile类 Bashrc类
交互式登录shell配置
非交互式登录shell配 置
全局配置文件 /etc/profile,/etc/profile.d/*.sh /etc/bashrc
个人配置文件 ~/.bash_profile ~/.bashrc
功能作用 定义环境变量,运行命令或脚本 定义命令别名和函数,定义本地 变量

编辑配置文件生效

修改profile和bashrc文件后需生效两种方法:

  • 重新启动shell进程

  • source|. 配置文件

注意:source 会在当前shell中执行脚本,所有一般只用于执行配置文件,或在脚本中调用另一个脚本的 场景

Bash 退出任务

保存在~/.bash_logout文件中(用户),在退出登录shell时运行

功能:

  • 创建自动备份

  • 清除临时文件

流程控制

条件选择

选择执行 if 语句
if COMMANDS; then COMMANDS; [ elif COMMANDS; then COMMANDS; ]... [ else COMMANDS; ] fi

#单分支
if 判断条件;then
   条件为真的分支代码
fi

str1=def;
if [ $str1 = "abc" ];then 
 echo "str1 is abc";
fi

#双分支
if 判断条件; then
条件为真的分支代码
else
条件为假的分支代码
fi

str1=def;
if [ $str1 = "abc" ];then 
 echo "str1 is abc";
else
 echo "str1 is not abc"
fi

#多分支
if 判断条件1; then
条件1为真的分支代码
elif 判断条件2; then
条件2为真的分支代码
elif 判断条件3; then
条件3为真的分支代码
...
else
以上条件都为假的分支代码
fi

str=$1;
if [ "$str" = "abc" ]; then
 echo "is abc";
elif [ "$str" = "def" ]; then
 echo "is def";
elif [ "$str" = "xyz" ]; then
 echo "is xyz";
else
 echo "not abc,not def"
fi

说明:

  • 多个条件时,逐个条件进行判断,第一次遇为“真”条件时,执行其分支,而后结束整个if语句

  • if 语句可嵌套

str1=$1
str2=$2
if [ "$str1" = "abc" ];then
 echo "str1 is abc";
 if [ "$str2" = "def" ];then
 echo "str2 is def";
 fi
else
 echo "str1 is not abc";
fi
条件判断 case 语句
case WORD in [PATTERN [| PATTERN]...) COMMANDS ;;]... esac
case 变量引用 in
PAT1)
分支1
 ;;
PAT2)
分支2
 ;;
...
*)
默认分支
 ;;
esac

#case支持glob风格的通配符
* #任意长度任意字符
? #任意单个字符
[] #指定范围内的任意单个字符
|   #或者,a|b

循环

循环执行介绍

将某代码段重复运行多次,通常有进入循环的条件和退出循环的条件

重复运行次数

  • 循环次数事先已知

  • 循环次数事先未知

常见的循环的命令:for, while, until

程序先进行语句判断,如真则执行循环语句,然后再进行语句判断,直至语句判断失败才跳出;

循环 for
for NAME [in WORDS ... ] ; do COMMANDS; done
#方式1
for 变量名  in 列表;do
循环体
done
#方式2
for 变量名  in 列表
do
循环体
done

执行机制:

  • 依次将列表中的元素赋值给“变量名”;每次赋值后即执行一次循环体;直到列表中的元素耗尽,循 环结束

  • 如果省略 [in WORDS ... ] ,此时使用位置参数变量 in "$@"

for 循环列表生成方式:

  • 直接给出列表

  • 整数列表:如 {start..end}

  • 返回列表的命令:如 $(COMMAND)

  • 使用glob,如:*.sh *

  • 变量引用,如:$@,$*,$#

双小括号方法,即((…))格式,也可以用于算术运算,双小括号方法也可以使bash Shell实现C语言风格的 变量操作:

for (( exp1; exp2; exp3 )); do COMMANDS; done
for ((控制变量初始化;条件判断表达式;控制变量的修正表达式))
do
循环体
done

示例
for((sum=0,i=1;i<=100;i++));do                       
       let sum+=i
done
echo sum=$sum
for((sum=0,i=1;i<=100;sum+=i,i++));do
 true
done
echo sum=$sum
[root@ubuntu1804 ~]#bash sum.sh
sum=5050
sum=5050

说明:

控制变量初始化:仅在运行到循环代码段时执行一次

控制变量的修正表达式:每轮循环结束会先进行控制变量修正运算,而后再做条件判断

循环 while
while CONDITION; do COMMANDS; done
while CONDITION; do
循环体
done
while CONDITION
do
 循环体
done

说明:

CONDITION:循环控制条件;进入循环之前,先做一次判断;每一次循环之后会再次做判断;条件为 “true”,则执行一次循环;直到条件测试状态为“false”终止循环,因此:CONDTION一般应该有循环控 制变量;而此变量的值会在循环体不断地被修正

进入条件:CONDITION为 true

退出条件:CONDITION为 false

无限循环

while true; do
循环体
done
while : ; do
循环体
done
while 特殊用法 while read

while 循环的特殊用法,遍历文件或文本的每一行

while read line; do
循环体
done < /PATH/FROM/SOMEFILE

说明:依次读取/PATH/FROM/SOMEFILE文件中的每一行,且将行赋值给变量line

循环 until
until CONDITION; do COMMANDS; done
until CONDITION; do
循环体
done

说明:

进入条件: CONDITION 为false

退出条件: CONDITION 为true

无限循环

until false; do
循环体
done
循环控制语句 continue

continue [N]:提前结束第N层的本轮循环,而直接进入下一轮判断;最内层为第1层

while CONDITION1; do
 CMD1
 ...
if CONDITION2; then
 continue
fi
 CMDn
 ...
 done
循环控制语句 break

break [N]:提前结束第N层整个循环,最内层为第1层

while CONDITION1; do
 CMD1
 ...
if CONDITION2; then
 break
fi
 CMDn
 ...
done
循环控制 shift 命令

shift [n] 用于将参量列表 list 左移指定次数,缺省为左移一次。

参量列表 list 一旦被移动,最左端的那个参数就从列表中删除。while 循环遍历位置参量列表时,常用到 shift

示例:
until [ -z "$1" ]; do
 echo "$@ "
 shift
done
[root@ubuntu2204 ~]# bash s.sh a b c d e f g
a b c d e f g 
b c d e f g 
c d e f g 
d e f g 
e f g 
f g 
g
循环与菜单 select
select NAME [in WORDS ... ;] do COMMANDS; done
select NAME in list ;do 
循环体命令
done

说明:

select 循环主要用于创建菜单,按数字顺序排列的菜单项显示在标准输出上,并显示 PS3 提示符, 等待用户输入

用户输入菜单列表中的某个数字,执行相应的命令

用户输入菜单列表中的某个数字,会将对应的WORD值赋值给NAME变量

用户输入被保存在内置变量 REPLY 中

select 是个无限循环,因此要用 break 命令退出循环,或用 exit 命令终止脚本。也可以按 ctrl+c 退出循环

select 经常和 case 联合使用

与 for 循环类似,可以省略 in list,此时使用位置参量

函数 function

函数介绍

函数 function

是由若干条shell命令组成的语句块,实现代码重用和模块化编程

它与shell程序形式上是相似的,不同的是它不是一个单独的进程,不能独立运行,而是shell程序的一部 分

函数和shell程序区别

  • Shell程序在子Shell中运行

  • 函数在当前Shell中运行。因此在当前Shell中,函数可对shell中变量进行修改

管理函数

函数由两部分组成:函数名和函数体

定义函数
#语法一
func_name(){
 ...函数体...
}
#语法二
function func_name {
 ...函数体...
}
#语法三
function func_name(){
 ...函数体...
} 
查看函数
#查看当前已定义的函数名
declare -F
#查看当前已定义的函数定义
declare -f
#查看指定当前已定义的函数名
declare -f func_name 
#查看当前已定义的函数名定义
declare -F func_name
删除函数
unset func_name

函数调用

函数的调用方式

  • 可在交互式环境下定义函数

  • 可将函数放在脚本文件中作为它的一部分

  • 可放在只包含函数的单独文件中

调用:函数只有被调用才会执行,通过给定函数名调用函数,函数名出现的地方,会被自动替换为函数 代码

函数的生命周期:被调用时创建,返回时终止

交互式环境调用函数

交互式环境下定义和使用函数

#定义
[root@ubuntu2204 ~]# test_func(){
> echo "this is cli function"
> }
#调用
[root@ubuntu2204 ~]# test_func
this is cli function
#查看
[root@ubuntu2204 ~]# declare -f test_func
test_func ()
{ 
    echo "this is cli function"
}
在脚本中定义及使用函数

函数在使用前必须定义,因此应将函数定义放在脚本开始部分,直至shell首次发现它后才能使用,调用 函数仅使用其函数名即可

使用函数文件

可以将经常使用的函数存入一个单独的函数文件,然后将函数文件载入shell,再进行调用函数 函数文件名可任意选取,但最好与相关任务有某种联系,例如:functions

一旦函数文件载入shell,就可以在命令行或脚本中调用函数。

可以使用delcare -f 或set 命令查看所有定义的函数,其输出列表包括已经载入shell的所有函数 若要改动函数,首先用unset命令从shell中删除函数。改动完毕后,再重新载入此文件

实现函数文件的过程:

  1. 创建函数文件,只存放函数的定义

  2. 在shell脚本或交互式shell中加载函数文件

  3. 调用函数

函数返回值

函数默认返回值是函数体中最后一条命令的退出状态码;

也可以使用return 自定义函数的返回值,在函数中使用 return,return 之后的语句将不会被执行

return 的用法:

return 语句 返回值
return 由return 语句的前一行命令执行结果决定
return 0 无错误返回
return 1-255 有错误返回

环境函数

类拟于环境变量,也可以定义环境函数,使子进程也可使用父进程定义的函数

定义环境函数:

export -f function_name 
declare -xf function_name

查看环境函数:

export -f
declare -xf

函数参数

函数可以接受参数:

  • 传递参数给函数:在函数名后面以空白分隔给定参数列表即可,如:testfunc arg1 arg2 ...

  • 在函数体中当中,可使用$1, $2, ...调用这些参数;还可以使用$@, $*, $#等特殊变量

函数变量

变量作用域:

变量类型 特点
普通变量 只在当前shell进程中有效,函数外定义,可以在函数内修改
环境变量 当前shell和子shell有效
本地变量 作用域在函数内,函数结束会被自动销毁

在函数中定义本地变量

local NAME=VALUE

#示例:本地变量只作用在函数内
var1=123
var_func1(){
 echo "func1 start ========================"
 echo $var1
 local var1=456
 local var2=789
 echo $var1 $var2
 echo "func1 end ========================="
}
echo $var1 $var2
var_func1
echo $var1 $var2
#执行
[root@ubuntu2204 ~]# bash var2.sh
123
func1 start ========================
123
456 789
func1 end =========================
123

函数递归

函数递归:

函数直接或间接调用自身,注意递归层数,可能会陷入死循环

递归特点:

  • 函数内部自已调用自已

  • 必须有结束函数的出口语句,防止死循环

阶乘

阶乘是基斯顿·卡曼(Christian Kramp,1760~1826)于 1808 年发明的运算符号,是数学术语。

一个正整数的阶乘(factorial)是所有小于及等于该数的正整数的积,并且0的阶乘为1。自然数n的阶乘 写作n!

阶乘公式

n!=1×2×3×...×(n-1)×n

0!=1, n!=(n-1)!×n

用递归实现阶乘

fac(){
 if [ $1 -gt 1 ];then
 echo $[$1 * $(fac $[$1-1])]
 else
 echo 1
 fi
}
fac $1

斐波拉契数列

斐波那契数列(Fibonacci sequence),又称黄金分割数列,因数学家莱昂纳多·斐波那契(Leonardo Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”

指的是这样一个数列:1、1、2、3、5、8、13、21、34、……

在数学上,斐波那契数列以如下被以递推的方法定义

F(0)=0,F(1)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 2,n ∈ N*)

用递归求斐波拉契数列第N项的值

fib(){
 if [ $1 -gt 1 ];then
 echo $[ $(fib $[$1-1]) + $(fib $[$1-2]) ]
 else
 echo $1
 fi
}
fib $1

逻辑炸弹

fork 炸弹是一种恶意程序,它的内部是一个不断在 fork 进程的无限循环,实质是一个简单的递归程序。 由于程序是递归的,如果没有任何限制,这会导致这个简单的程序迅速耗尽系统里面的所有资源

:(){ :|:& };:
bomb(){ bomb | bomb & };bomb

其它脚本相关工具

信号捕捉 trap

trap 命令可以捕捉信号,修改信号原来的功能,实现自定义功能

在脚本或程序的执行过程中,我们可以通过发送信号的方式,打断或终止程序的执行过程,为了避免这 种情况,我们可以使用信号捕捉,来自定义信号处理。

trap [-lp] [[arg] signal_spec ...]

#常用选项
-l #显示所有信号
-p #显示所有自定义的信号


trap 'command' signal #自定义指定信号的处理方式
trap '' signal #忽略指定的信号
trap '-' signal #恢复信号默认操作
trap func EXIT #退出时执行func

#查看所有信号
trap -l

#信号的三种表示方法
3) SIGQUIT
3 #信号ID
SIGQUIT #完整写法,大小写都支持
QUIT #简短写法,大小写都支持

创建临时文件 mktemp

mktemp 命令用于创建并显示临时文件,可避免冲突

mktemp [OPTION]... [TEMPLATE]

#常用选项
-d|--directory     #创建目录
-u|--dry-run       #只输出命令,不执行
-p DIR|--tmpdir[=DIR]   #指明临时文件所存放目录位置
-t                 #将文件保存到$TMPDIR 定义的目录中,如果该变量未定义,则保存到/tmp 目录中

安装复制文件 install

install 功能相当于cp,chmod,chown,chgrp ,mkdir 等相关工具的集合

install [OPTION]... [-T] SOURCE DEST
install [OPTION]... SOURCE... DIRECTORY
install [OPTION]... -t DIRECTORY SOURCE...
install [OPTION]... -d DIRECTORY...

#常用选项
-m|--mode=MODE #指定权限,默认755
-v|--verbose #显示过程
-o|--owner=OWNER #指定属主
-g|--group=GROUP #指定属组
-d|--directory DIR #指定目录,如果不存在就创建

数组 array

数组介绍

变量:存储单个元素的内存空间

数组:存储多个元素的连续的内存空间,相当于多个变量的集合

数组名和索引

索引的编号从0开始,属于数值索引

索引可支持使用自定义的格式,而不仅是数值格式,即为关联索引,bash 4.0版本之后开始支持 bash的数组支持稀疏格式(索引不连续)

声明数组

#普通数组可以不事先声明,直接使用
declare -a ARRAY_NAME
#关联数组必须先声明,再使用
declare -A ARRAY_NAME

注意:两者不可相互转换

数组赋值

一次只赋值一个元素

ARRAY_NAME[INDEX]=VALUE

#示例
[root@ubuntu2204 ~]# weekdays[0]="Sunday"
[root@ubuntu2204 ~]# weekdays[4]="Thursday"

一次赋值全部元素

ARRAY_NAME=("VAL1" "VAL2" "VAL3" ...)

#示例
[root@ubuntu2204 ~]# title=("ceo" "coo" "cto")
[root@ubuntu2204 ~]# num=({0..10})
[root@ubuntu2204 ~]# alpha=({a..g})
[root@ubuntu2204 ~]# file=( *.sh )

只赋值特定元素

ARRAY_NAME=([0]="VAL1" [3]="VAL2" ...)

#示例
[root@ubuntu2204 ~]# weekdays=([0]="Sunday" [4]="Thursday")

交互式数组值对赋值

read -a ARRAY

#示例
[root@ubuntu2204 ~]# read -a test
a b c d

显示所有数组

declare -a

引用数组

#如果省略[INDEX]表示引用下标为0的元素
${ARRAY_NAME[INDEX]}

#示例
[root@ubuntu2204 ~]# declare -a title=([0]="ceo" [1]="coo" [2]="cto")
[root@ubuntu2204 ~]# echo ${title[1]}
coo
[root@ubuntu2204 ~]# echo ${title}
ceo
[root@ubuntu2204 ~]# echo ${title[2]}
cto
[root@ubuntu2204 ~]# echo ${title[3]}
[root@rocky86 ~]

#区分这三种写法
[root@ubuntu2204 ~]# echo $title
ceo
[root@ubuntu2204 ~]# echo ${title[0]}
ceo
[root@ubuntu2204 ~]# echo $title[0]
ceo[0]

引用数组所有元素

${ARRAY_NAME[*]}
${ARRAY_NAME[@]}

数组的长度,即数组中元素的个数(多加一个#号)

${#ARRAY_NAME[*]}
${#ARRAY_NAME[@]}

数组的所有下标(多一个!号)

${!ARRAY_NAME[*]}
${!ARRAY_NAME[@]}

删除数组

删除数组中的某元素,会导致稀疏格式

unset ARRAY[INDEX]

#删除整个数组
unset ARRAY

数组数据处理

数组切片

${ARRAY[@]:offset:number}
${ARRAY[*]:offset:number}

offset #要跳过的元素个数
number #要取出的元素个数

#取偏移量之后的所有元素
{ARRAY[@]:offset}
{ARRAY[*]:offset}

${ARRAY[*]::number} #取数组中最前面的 number 个元素

向数组中追加元素

ARRAY[${#ARRAY[*]}]=value
ARRAY[${#ARRAY[@]}]=value

关联数组

关联数组与普通数组区别:

  • 关联数组要先声明,才能使用,普通数组可以不用声明

  • 关联数组可以自定义下标,普通数组必须用数字

declare -A ARRAY_NAME 
ARRAY_NAME=([idx_name1]='val1' [idx_name2]='val2‘...)

字符串处理

字符串切片

基于偏移量取字符串
${#var} #返回字符串变量var的字符的长度,一个汉字算一个字符

${var:offset} #返回字符串变量var中从第offset个字符后(不包括第offset个字符)的字符开始,到最后的部分,offset的取值在0 到 ${#var}-1 之间(bash4.2后,允许为负值)

${var:offset:number} #返回字符串变量var中从第offset个字符后(不包括第offset个字符)的字符开始,长度为number的部分

${var: -length} #取字符串的最右侧几个字符, 注意:冒号后必须有一空白字符

${var:offset:-length} #从最左侧跳过offset字符,一直向右取到距离最右侧lengh个字符之前的内容,即:掐头去尾

${var: -length:-offset} #先从最右侧向左取到length个字符开始,再向右取到距离最右侧offset个字符之间的内容,注意:-length前空格,并且length必须大于offset
基于模式取子串
#其中word可以是指定的任意字符,自左而右,查找var变量所存储的字符串中,第一次出现的word, 删除字符串开头至第一次出现word字符串(含)之间的所有字符,即懒惰模式,以第一个word为界删左留右
${var#*word}

#从var变量的值中删除以word开头的部分
${var#word}

#同上,贪婪模式,不同的是,删除的是字符串开头至最后一次由word指定的字符之间的所有内容,即贪婪模式,以最后一个word为界删左留右
${var##*word}
${var##word}

查找替换

#查找var所表示的字符串中,第一次  被pattern所匹配到的字符串,以substr替换之,懒惰模式
${var/pattern/substr}

#查找var所表示的字符串中,所有   能被pattern所匹配到的字符串,以substr替换之,贪婪模式
${var//pattern/substr}

#查找var所表示的字符串中,行首  被pattern所匹配到的字符串,以substr替换之
${var/#pattern/substr}

#查找var所表示的字符串中,行尾  被pattern所匹配到的字符串,以substr替换之
${var/%pattern/substr}

查找并删除

#删除var表示的字符串中第一次 被pattern匹配到的字符串,懒惰模式
${var/pattern}

#删除var表示的字符串中所有 被pattern匹配到的字符串,贪婪模式
${var//pattern}

#删除var表示的字符串中所有以pattern为行首  匹配到的字符串
${var/#pattern}

#删除var所表示的字符串中所有以pattern为行尾  所匹配到的字符串
${var/%pattern}

字符大小写转换

#把var中的所有小写字母转换为大写
${var^^}
#把var中的所有大写字母转换为小写
${var,,}

#示例
[root@ubuntu2204 ~]# str=abcd1234ABCD12345
#所有小写转大写
[root@ubuntu2204 ~]# echo ${str^^}
ABCD1234ABCD12345
#所有大写转小写
[root@ubuntu2204 ~]# echo ${str,,}
abcd1234abcd12345
#tr实现大小写转换
[root@ubuntu2204 ~]# echo $str | tr 'a-z' 'A-Z'
ABCD1234ABCD12345

变量扩展

#扩展以所有prefix开头的变量
${!prefix*}
${!prefix@}

高级变量

高级变量赋值

$str 为变量名,expr 为具体字符串 这些组合可以省掉一些 if,else 的判断代码

变量配置方式 str没有配置 str为空字符串 str己配置为非空字符串
var=${str-expr} var=expr var= var=$str
var=${str:-expr} var=expr var=expr var=$str
var=${str+expr} var= var=expr var=expr
var=${str:+expr} var= var= var=expr
var=${str=expr} str=expr; var=expr str不变; var= str不变; var=$str
var=${str:=expr} str=expr; var=expr str=expr; var=expr str不变; var=$str
var=${str?expr} expr 输出至 stderr var= var=$str
var=${str:?expr} expr 输出至 stderr expr输出至stderr var=$str

高级变量用法-有类型变量

Shell变量一般是无类型的,但是bash Shell提供了declare和typeset两个命令用于指定变量的类型,两 个命令是等价的

declare [-aAfFgilnrtux] [-p] [name[=value] ...]

#选项:
-f #显示已定义的所有函数名及其内容
-F #仅显示已定义的所有函数名
-p   #显示每个变量的属性和值
-a #声明或显示定义为数组的变量
-A #将变量定义为关联数组      
-i #声明或显示定义为整型的变量
-l #声明或显示定义为小写的变量
-n   #变量引用另外一个变量的值
-r #声明或显示只读变量
-t   #声明或显示具有trace(追踪)属性的变量
-u #声明或显示定义为大写的变量
-x #显示环境变量和函数,相当于export 

变量间接引用

eval命令

eval命令将会首先扫描命令行进行所有的置换,然后再执行该命令。该命令适用于那些一次扫描无法实 现其功能的变量,该命令对变量进行两次扫描

示例

[root@ubuntu2204 ~]# CMD=whoami
[root@ubuntu2204 ~]# echo $CMD
whoami
[root@ubuntu2204 ~]# eval $CMD
root
[root@ubuntu2204 ~]# n1=6
[root@ubuntu2204 ~]# echo {1..$n1}
{1..6}
#两次展开
[root@ubuntu2204 ~]# eval echo {1..$n1}
1 2 3 4 5 6
间接变量引用

如果第一个变量的值是第二个变量的名字,从第一个变量引用第二个变量的值就称为间接变量引用 variable1的值是variable2,而variable2又是变量名,variable2的值为value,间接变量引用是指通过 variable1获得变量值value的行为

variable1=variable2
variable2=value

#示例
[root@ubuntu2204 ~]# var1=str
[root@ubuntu2204 ~]# str=abcd
[root@ubuntu2204 ~]# echo $var1
str
[root@ubuntu2204 ~]# echo \$$var1
$str
[root@ubuntu2204 ~]# eval echo \$$var1
abcd

bash Shell提供了两种格式实现间接变量引用

#方法1
#变量赋值
eval tempvar=\$$variable1
#显示值
eval echo \$$variable1
eval echo '$'$variable1
echo $tmpvar

#方法2
#变量赋值
tempvar=${!variable1}
#显示值
echo ${!variable1}

#示例
[root@ubuntu2204 ~]# ceo=name
[root@ubuntu2204 ~]# name=123
[root@ubuntu2204 ~]# eval echo \$$ceo
123

你可能感兴趣的:(运维,学习,linux)