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

Linux 入门到精通,真的不用背命令!零基础小白靠「场景化学习法」,3 个月拿下运维 offer,第二十四天

Shell脚本变量用法详解

变量基础

变量是命名的内存空间,用于存储数据并通过变量名引用。Shell脚本中变量无需声明类型,直接赋值即可使用。

变量类型

Shell变量主要分为以下几类:

  • 内置变量
    由系统预定义,如 PS1(提示符格式)、PATH(命令搜索路径)、UID(用户ID)、HOSTNAME(主机名)、HISTSIZE(历史记录条数)。

  • 用户自定义变量
    由用户根据需求定义,命名需遵循规则(见下文)。

  • 预定义变量
    $?(上一条命令的退出状态)、$$(当前进程PID)、$0(脚本名称)。

  • 位置变量
    通过 $1$2...$9 引用脚本参数,${10} 及以上需加大括号。

变量数据类型

Shell变量默认存储字符串,数值实际为字符串形式。

  • 字符串:如 name="John"
  • 数值:仅支持整数运算,浮点数需借助外部工具(如 bc)。
变量命名规则
  • 禁止使用保留字(如 iffor)。
  • 仅允许字母、数字、下划线,且不能以数字开头。
  • 推荐命名规范:
    • 普通变量:小写驼峰式(如 userName)。
    • 环境变量:全大写加下划线(如 LOG_PATH)。
    • 局部变量:函数内使用,前缀加 local(如 local count=1)。
变量定义与引用
  • 定义普通变量

    var_name="value"  # 等号两侧无空格
    

    引用变量时需加 $

    echo $var_name
    # 或
    echo ${var_name}  # 推荐,避免歧义
    

  • 环境变量
    通过 export 提升为环境变量,子进程可继承:

    export PATH=$PATH:/new/path
    

  • 本地变量(函数内)
    使用 local 声明,作用域限于函数:

    function demo() {local local_var="value"echo $local_var
    }
    

变量作用域
  • 普通变量:仅当前Shell进程有效。
  • 环境变量:当前Shell及其子进程有效。
  • 本地变量:仅限函数内部。
示例:数值运算

Shell中整数运算需用 $(( ))let

sum=$(( 1 + 2 ))  # 输出3
let "sum *= 2"    # 输出6

浮点数运算需借助 bc

echo "scale=2; 3/2" | bc  # 输出1.50

注意事项
  • 未定义的变量引用视为空字符串。
  • 变量赋值时避免空格:var=value 正确,var = value 错误。
  • 引号使用:
    • 双引号允许变量扩展:echo "$var"
    • 单引号禁止扩展:echo '$var' 输出字面量 $var

变量赋值:

name="value"
​
value可以是以下多种类型
直接字符串:name='root'
变量引用:name="$USER"
命令应用:name=`command`  || name=$(command)
通配符:FILE=/etc/* /*表示etc目录下所有的文件名*/

注意:变量赋值是临时生效,当退出终端后,变量会自动删除,无法持久保存。

变量引用:

$name
${name}

弱引用和强引用:

  • “$name”:弱引用,其中的变量引用会被替换成为变量值

  • ‘$name’:强引用,其中的变量引用不会被替换成变量值,而保持原字符串

实例:

[root@localhost ~]# name='Mike'
[root@localhost ~]# NAME="$USER"
[root@localhost ~]# hostname=`hostname`
[root@localhost ~]# echo "My name is $name"
My name is Mike
[root@localhost ~]# echo "My name is $NAME"
My name is root
[root@localhost ~]# echo "My hostname is $hostname"
My hostname is localhost.localdomain
[root@localhost ~]# 
​
[root@localhost ~]# NUM=`seq 10`
[root@localhost ~]# echo $NUM
1 2 3 4 5 6 7 8 9 10
[root@localhost ~]# echo "$NUM"
1
2
3
4
5
6
7
8
9
10
[root@localhost ~]#

查看已定义的所有变量:

[root@localhost ~]#set

删除变量

[root@localhost ~]#unset shellname1 shellname2
//实例:
[root@localhost ~]# echo $name 
Mike
[root@localhost ~]# unset name
[root@localhost ~]# echo $name 
​
[root@localhost ~]# 

实例:"{}"的使用

[root@localhost ~]# NAME=mage
[root@localhost ~]# AGE=20
[root@localhost ~]# echo $NAME
mage
[root@localhost ~]# echo $AGE
20
[root@localhost ~]# echo $NAME $AGE
mage 20
[root@localhost ~]# echo $NAME_$AGE
20
[root@localhost ~]# echo ${NAME}_$AGE
mage_20
[root@localhost ~]# 

显示系统信息

[root@localhost ~]# vim shell/OS.sh  
#!/bin/bash
RED="\E[1;31m"
GREEB="\E[1;32m"
END="\E[0m"
echo -e "\E[1;32m----------Host systeminfo----------$END"
echo -e "HOSTNAME: $RED `hostname`$END"
echo -e "IPADDR:   $RED `ifconfig ens160 | grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}' | head -n1` $END"
echo -e "OSVERSION: $RED `cat /etc/redhat-release`$END"
echo -e "KERNEL:   $RED `uname -r`$END"
echo -e "CPU:       $RED `lscpu | grep "型号名称:" | tr -s ' ' ' '|cut -d ' ' -f 2-5` $END"
echo -e "MEMORY:   $RED `free -h | grep Mem | tr -s ' ' ' '|cut -d ' ' -f 4` $END"
echo -e "DISK:     $RED `lsblk | grep '^sda' | tr -s ' ' | cut -d ' ' -f 4` $END"
echo -e "\E[1;32m----------       END     ----------$END"
[root@localhost ~]# chmod +x shell/OS.sh 
[root@localhost shellScript]# ./os.sh 
----------Host systeminfo----------
HOSTNAME:  localhost.localdomain
IPADDR:    192.168.115.213 
OSVERSION:  CentOS Linux release 7.9.2009 (Core)
KERNEL:    3.10.0-1160.el7.x86_64
CPU:        11th Gen Intel(R) Core(TM) 
MEMORY:    1.0G 
DISK:      200G 
----------       END     ----------

利用变量实现动态命令

[root@localhost ~]# CMD=hostname
[root@localhost ~]# $CMD
localhost.localdomain
[root@localhost ~]# 
环境变量特性:
  1. 继承性:子进程(包括孙子进程)可以继承父进程的环境变量,但父进程无法获取子进程修改后的变量值

  2. 单向传递:当子进程修改继承的环境变量时,新的值会传递给后续的子进程(孙子进程等)

使用场景:
  • 主要用于配置文件
  • 脚本中较少使用
课程对比: 普通变量与环境变量的作用域差异
[root@localhost ~]# vim shell/father.sh 
#!/bin/bash
NAME=father
echo "father.sh:NAME=$NAME"
echo "fatther is PID=$BASHPID"
shell/son.sh
​
[root@localhost ~]#vim shell/son.sh
#!/bin/bash
echo "son.sh:NAME=$NAME"
NAME=son
echo "son.sh:NAME=$NAME"
echo "son.sh PID is $BASHPID"
echo "son.sh father pid is $PPID"
sleep 100
​
[root@localhost ~]#chmod -R +x shell/*
​
[root@localhost ~]# ./shell/father.sh 
father.sh:NAME=father
fatther is PID=12053
son.sh:NAME=
son.sh:NAME=son
son.sh PID is 12054
son.sh father pid is 12053
​
#子进程无法使用父进程的变量,需要自己赋值

变量声明和赋值:

export name=VALUE
declare -x name =VALUE
​
#或者先赋值再声明~
​
value可以是以下多种类型
直接字符串:name='root'
变量引用:name="$USER"
命令应用:name=`command`  || name=$(command)
通配符:FILE=/etc/* /*表示etc目录下所有的文件名*/

declare 命令详解

declare 是 shell 内置命令,具有以下功能:

  1. 变量声明:第一种语法用于声明变量并设置其属性(如 [rix] 等)
  2. 函数显示:第二种语法用于显示 shell 函数信息

当不带任何参数执行时,declare 会显示当前环境中的所有 shell 变量和函数(效果等同于 set 命令)

declare [+/-][rxi][变量名称=设置值] 或 declare -f
参数说明:

+/-  "-“可用来指定变量的属性,”+"则是取消变量所设的属性。

-f   仅显示函数

r   将变量声明为只读变量。注意,一旦设置为只读变量,既不能修改变量的值也不能删除变量,甚至不能通过+r取消只 读属性

x   指定的变量会成为环境变量,可供shell以外的程序来使用

i   将变量声明为整数型(integer)

p 显示指定变量的被声明类型。

1.声明整数型变量
#!/bin/bash
declare -i ab //声明整数型变量
ab=56 //改变变量内容
echo $ab //显示变量内容
​
--->
56
2.改变变量属性
#!/bin/bash
#声明整数型变量
declare -i ef 
ef=1
echo $ef
#变量赋值,赋予文本值
ef="wer"
echo $ef
#取消变量属性
declare +i ef
ef="wer"
echo $ef
3.设置变量只读
#!/bin/bash
declare -r ab #设置变量为只读
ab=88 #改变变量内容
echo $ab #显示变量内容
​
--->
declare.sh:行3: ab: 只读变量
4.声明数组变量
#!/bin/bash
#声明数组变量
declare -a cd
cd[0]=a
cd[1]=b
cd[2]=c
#输出数组的指定内容
echo ${cd[1]}
#显示整个数组变量内容
echo ${cd[@]}
5.显示函数
#!/bin/bash
#声明函数
declare -f 
function command_not_found_handle(){if [ -x /usr/lib/command_not_found_handle ];then/usr/bin/python /usr/lib/command_not_found_handle -- $1;return $?;elseif [ -x /usr/share/command_not_found_handle ];then/usr/bin/python /usr/share/command_not_found_handle --$1;return $?;elsereturn 127;fi;fi;
}
变量引用:
$name
${name}
完善课程导入:
[root@localhost ~]# vim shell/father.sh 
#!/bin/bash
NAME=father
export NAME
echo "father.sh:NAME=$NAME"
echo "fatther is PID=$BASHPID"
shell/son.sh
​
[root@localhost ~]#vim shell/son.sh
#!/bin/bash
echo "son.sh:NAME=$NAME"
NAME=son
echo "son.sh:NAME=$NAME"
echo "son.sh PID is $BASHPID"
echo "son.sh father pid is $PPID"
sleep 100
​
[root@localhost ~]#chmod -R +x shell/*
​
[root@localhost ~]# ./shell/father.sh 
father.sh:NAME=father
fatther is PID=12053
son.sh:NAME=father
son.sh:NAME=son
son.sh PID is 12054
son.sh father pid is 12053
[root@localhost ~]# ./shell/father.sh 
father.sh:NAME=father
fatther is PID=12142
son.sh:NAME=father
son.sh:NAME=son
son.sh PID is 12143
son.sh father pid is 12142#父进程定义了一个环境变量,在子进程上可以进行调用#父进程无法使用子进程的变量#子进程自己定义了一个同名变量,就覆盖环境变量

显示所有环境变量:

[root@localhost ~]# env
[root@localhost ~]# printenv
[root@localhost ~]# export
[root@localhost ~]# declare -x

删除变量

[root@localhost ~]#unset shellname1 shellname2

Bash内建的环境变量

PATH
SHELL
USER
UID
PWD
SHLVL #shell的嵌套层数,即深度
LANG
MAIL
HOSTNAME
HISTSIZE
_      #下划线,表示前一命令的最后一个参数
只读变量

只读变量:只能声明定义,但后续不能修改和删除

声明只读变量:

readonly name
declare -r name

查看只读变量:

readonly [-p]
declare -r
 位置变量

位置变量:在Bash Shell中内置的变量,在脚本代码中调用命令行传递给脚本的参数

$1,$2,... 对应第一个,第二个等参数,shift[n]换位置,最多9个
#预定义变量
$0  命令本身,包括路径
$*  传递给脚本的所有参数,全部参数合成一个字符串
$@  传递给脚本的所有参数,每个参数为独立字符串
$#  传递给脚本的参数的个数
$?  上个命令的退出状态,或函数的返回值
$$  当前shell进程ID。对于Shell脚本,就是这些脚本所在的进程ID
​
注意:$@,$*只有被双引号括起来的时候才会有差异

清空所有位置变量

set --
//写在脚本内部

实例演示1:

[root@localhost ~]# vim shell/ARG.sh
#!/bin/bash
echo "1st arg is $1"
echo "2st arg is $2"
echo "3st arg is $3"
echo "4st arg is $4"
echo "The number of are is $#"
echo "All args are $*"
echo "All args are $@"
echo "The scriptname is `basename $0`"
[root@localhost ~]# chmod +x shell/ARG.sh 
[root@localhost ~]# shell/ARG.sh {1..10}
1st arg is 1
2st arg is 2
3st arg is 3
4st arg is 4
The number of are is 10
All args are 1 2 3 4 5 6 7 8 9 10
All args are 1 2 3 4 5 6 7 8 9 10
The scriptname is ARG.sh
[root@localhost ~]# 

实例演示2:编写一个移动文件脚本

[root@localhost ~]# vim shell/move.sh
#!/bin/bash
WANGING_COLOR="echo -e \E[1;31m"
END="\E[0m"
DIR=/tmp/`date +%F_%H-%M-%S`
mkdir $DIR
mv $*  $DIR
${WANGING_COLOR} MOVE $* to $DIR $END
[root@localhost ~]# chmod +x shell/move.sh
[root@localhost ~]# touch {a,b,c}
[root@localhost ~]# ls
a  anaconda-ks.cfg  b  c  shell
[root@localhost ~]# shell/move.sh a b cMOVE a b c to /tmp/2022-08-16_10-07-55 
[root@localhost ~]# tree /tmp/
/tmp/
└── 2022-08-16_10-07-55├── a├── b└── c
​
1 directory, 3 files
[root@localhost ~]# 
退出状态码变量

进程执行后,将使用变量 ? 保存状态码的相关数字,不同的值反应成功与失败, ?保存状态码的相关数字,不同的值反应成功与失败, ?保存状态码的相关数字,不同的值反应成功与失败,的取值范围为[0,255]

$?的值为0 代表成功
$?的值不为0 代表失败

用户可以在脚本中使用以下命令自定义退出状态码

exit [n]

实例:

[root@localhost ~]# ping -c 2 www.baidu.com > /dev/null 
[root@localhost ~]# echo $?
0
[root@localhost ~]# cmd
-bash: cmd: 未找到命令
[root@localhost ~]# echo $?
127
[root@localhost ~]# 
​

注意:

  • 脚本中一旦遇到了exit命令,脚本会立即终止;终止退出状态取决于exit命令后面的数字

  • 如果未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一条命令的状态码

实例1:$?获取上一个命令的退出状态

#!/bin/bash
if [ "$1"==100 ];thenexit 0 #参数正确,退出状态为0
elseexit 1 #参数错误,退出状态为1
fi

exit表示退出当前 Shell 进程,我们必须在新进程中运行 test.sh,否则当前 Shell 会话(终端窗口)会被关闭,我们就无法取得它的退出状态了

[root@localhost re_study]# bash test.sh 100
[root@localhost re_study]# echo $?
0
[root@localhost re_study]# bash test.sh 99
[root@localhost re_study]# echo $?
1
[root@localhost re_study]# 

实例2:$?获取函数的返回值

#!/bin/bash
#得到两个数相加的和
function add(){return `expr $1 + $2`
}
add 23 50 #调用函数
echo $? #获取函数返回值
# 运行结果:
[root@localhost re_study]# bash test.sh
73

http://www.xdnf.cn/news/19684.html

相关文章:

  • 鸿蒙Next开发指南:XComponent与Progress组件的深度解析与实践
  • 在 PySpark 中解锁窗口函数的力量,实现高级数据转换
  • 数控机床相邻轨迹最大过渡速度计算方法介绍
  • 【Kubernetes】知识点2
  • 【数学建模学习笔记】时间序列分析:LSTM
  • Vue 3 + TypeScript 现代前端开发最佳实践(2025版指南)
  • 【完整源码+数据集+部署教程】PHC桩实例分割系统源码和数据集:改进yolo11-Faster-EMA
  • 黄金金融期货数据API对接技术文档
  • nmap扫描端口,netstat
  • 土地退化相关
  • Axure: 平滑折线图
  • Apache Doris:重塑湖仓一体架构的高效计算引擎
  • 文件页的预取逻辑
  • 小兔鲜儿项目
  • 树莓派网页监控
  • 从 Arm Compiler 5 迁移到 Arm Compiler 6
  • 2025 随身 WIFI 行业报告:从拼参数到重体验,华为 / 格行 / 中兴技术差异化路径解析
  • 梳理一下 @types/xxx
  • java面试中经常会问到的多线程问题有哪些(基础版)
  • think
  • ubuntu系统设置中文失败问题
  • grpc-swift-2 学习笔记
  • 均匀分布直线阵的常规波束形成方位谱和波束图
  • (Arxiv-2025)ConceptMaster:基于扩散 Transformer 模型的多概念视频定制,无需测试时微调
  • 【2025终极对决】Python三大后端框架Django vs FastAPI vs Robyn,你的选择将决定项目生死?
  • [光学原理与应用-366]:ZEMAX - 用成像原理说明人眼为什么能看清物体?
  • 两款超实用办公插件推荐:Excel聚光灯与Word公文排版
  • MySQL 多表查询方法
  • Spring Boot 全局字段处理最佳实践
  • mysql初学者练习题(从基础到进阶,相关数据sql脚本在最后)