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

4.Shell脚本修炼手册---变量进阶知识

4. Shell 变量进阶知识

文章目录

    • 4. Shell 变量进阶知识
      • 4.1 Shell 中的特殊变量
        • 4.1.1 位置参数变量:获取脚本的输入参数
        • 4.1.2 进程状态变量:获取命令执行的状态信息
      • 4.2 Shell 内置命令
        • 4.2.1 `echo`:输出内容到终端*
        • 4.2.2 `read`:从终端读取输入
        • 4.2.3 `exec`:替换当前进程执行命令
      • 4.3 Shell 变量子串:截取和处理变量内容
        • 4.3.1 常用变量子串语法
        • 4.3.2 变量子串实践示例
        • 4.3.3 实验应用案例

4.1 Shell 中的特殊变量

在 Shell 脚本中,有一些自带的 “特殊变量”,它们不需要我们手动定义,却能帮我们快速获取脚本运行时的关键信息(比如参数、进程状态等)。下面我们逐个认识这些变量,以及它们的具体用法。

4.1.1 位置参数变量:获取脚本的输入参数

当我们运行一个 Shell 脚本时,经常需要给它传递一些参数(比如 bash script.sh 参数1 参数2)。位置参数变量就是用来获取这些参数的工具,常见的有以下几个:

变量作用说明
$0获取当前执行的 Shell 脚本的文件名(如果执行时带路径,会包含完整路径)
$n获取第 n 个参数(n 是数字,比如 $1 是第 1 个参数;n>9 时需用 ${10}
$#获取传递给脚本的参数总个数
$*获取所有参数(不加引号时和 $@ 一样;加引号 "$*" 时,所有参数会被合并成一个字符串)
$@获取所有参数(不加引号时和 $* 一样;加引号 "$@" 时,每个参数保持独立字符串)

实验:位置参数变量的使用演示 实验流程:创建一个脚本 showargs.sh,在脚本中打印各种位置参数变量,然后传递参数执行脚本,观察输出结果。

步骤 1:创建脚本并添加内容

[bq@shell ~]$ vim showargs.sh
#!/bin/bash
# 打印脚本文件名($0)
echo "脚本文件名:$0"
# 打印第1个参数($1)
echo "第1个参数:$1"
# 打印第2个参数($2),(到$9前以此类推)
echo "第2个参数:$2"
# 错误示范:n>9 时直接用 $10 会被解析为 $1+0
echo "错误的第10个参数(\$10):$10"
# 正确示范:n>9 时需用 ${10}
echo "正确的第10个参数(\${10}):${10}"
# 打印参数总个数($#)
echo "参数总个数:$#"
# 打印所有参数(不加引号的 $*)
echo "所有参数(\$*):$*"
# 打印所有参数(不加引号的 $@)
echo "所有参数(\$@):$@"
# 打印所有参数(加引号的 "$@",保持参数独立性)
echo "所有参数(\"$@\"):$@"

步骤 2:执行脚本并传递参数 我们传递 a到z 共 26 个参数(用 {a..z} 快速生成):

[bq@shell ~]$ bash showargs.sh {a..z}

步骤 3:观察输出并理解含义

脚本文件名:showargs.sh  # $0 输出文件名
第1个参数:a            # $1 输出第1个参数a
第2个参数:b            # $2 输出第2个参数b
错误的第10个参数($10):a0  # $10 被解析为 $1(a)+0,所以是a0
正确的第10个参数(${10}):j  # ${10} 正确获取第10个参数j(a是第1个,j是第10个)
参数总个数:26          # $# 输出参数总数26
所有参数($*):a b c d ... z  # 所有参数用空格分隔
所有参数($@):a b c d ... z  # 不加引号时和 $* 一致
所有参数("$@"):a b c d ... z  # 加引号时保持每个参数独立

实际应用案例:简化命令执行 比如我们可以写一个脚本 ssh_ctl.sh,通过传递参数控制 sshd 服务的启动 / 停止 / 状态:

#!/bin/bash
# 接收第1个参数($1)作为操作命令(start/stop/status),传递给 systemctl 控制 sshd
systemctl $1 sshd

执行效果:

# 停止 sshd 服务($1 为 stop)
[bq@shell ~]$ sudo bash ssh_ctl.sh stop
# 查看 sshd 状态($1 为 status)
[bq@shell ~]$ sudo bash ssh_ctl.sh status
# 启动 sshd 服务($1 为 start)
[bq@shell ~]$ sudo bash ssh_ctl.sh start
4.1.2 进程状态变量:获取命令执行的状态信息

除了输入参数,我们还经常需要知道 “上一个命令是否执行成功”“当前脚本的进程号” 等信息,这就需要用到进程状态变量。

变量作用说明
$?获取上一个命令的执行结果(0 表示成功,非 0 表示失败,最常用)
$$获取当前脚本 / Shell 的进程号(PID)
$!获取上一个后台运行进程的 PID
$_获取上一个命令中最后一个参数

1. $?:判断命令是否执行成功 $? 是最常用的进程状态变量,它的返回值规则是:

  • 0:上一个命令执行成功
  • 非 0:上一个命令执行失败(具体数值代表不同错误,可通过 man 命令 查看说明)

示例验证

# 执行成功的命令(ls 查看存在的目录)
[bq@shell ~]$ ls hello  # 假设 hello 是存在的目录
hello
[bq@shell ~]$ echo $?   # 输出 0,代表成功
0# 执行失败的命令(ls 查看无权限的目录)
[bq@shell ~]$ ls /root  # 普通用户无权限访问 /root
ls: 无法打开目录/root: 权限不够
[bq@shell ~]$ echo $?   # 输出 2,代表失败(通过 man ls 可知 2 是“严重错误”)
2

通过 man ls 可以查看 ls 命令的退出码含义:

Exit status:0  表示成功1  表示轻微问题(如无法访问子目录)2  表示严重问题(如无法访问命令行参数指定的路径)

**2. `

(:获取当前进程的 PID**\ )

` 会返回当前 Shell 或脚本的进程号,可用于杀死当前进程(不常用,了解即可)。

示例验证

# 查看当前 Shell 的 PID
[bq@shell ~]$ echo $$
2447  # 假设当前 Shell 的 PID 是 2447# 用 kill -9 强制终止当前进程(会断开连接)
[bq@shell ~]$ kill -9 $$
Connection closed by foreign host.  # 进程被杀死,连接断开

3. $!:获取后台进程的 PID 当我们用 & 让命令在后台运行时,$! 可以获取它的 PID,方便后续管理(如杀死后台进程)。

示例验证

# 让 md5sum 在后台计算 /dev/zero(一个无限输出的设备)
[bq@shell ~]$ md5sum /dev/zero &
[1] 2611  # 后台进程的 PID 是 2611# 用 $! 获取后台进程的 PID
[bq@shell ~]$ echo $!
2611  # 输出刚才的 PID# 查看该 PID 对应的进程
[bq@shell ~]$ ps o pid,%cpu,%mem,command $!PID %CPU %MEM COMMAND2611 99.1  0.0 md5sum /dev/zero  # 确实是后台运行的 md5sum# 用 $! 杀死后台进程
[bq@shell ~]$ kill $!
[1]+  Terminated              md5sum /dev/zero  # 进程被终止

4. $_:获取上一个命令的最后一个参数 $_ 会保存上一个命令中最后一个参数,方便快速复用。

示例验证

# 执行一个包含多个参数的命令
[bq@shell ~]$ ls /etc/hosts /etc/fstab /etc/hostname
/etc/fstab  /etc/hostname  /etc/hosts# 用 $_ 获取最后一个参数(/etc/hostname)
[bq@shell ~]$ cat $_  # 等效于 cat /etc/hostname
bq-shell  # 输出 /etc/hostname 的内容# 验证结果
[bq@shell ~]$ cat /etc/hostname
bq-shell  # 和上面的输出一致

4.2 Shell 内置命令

Shell 自带了一些 “内置命令”(无法在目录中找到,由 Shell 直接提供),它们用于完成一些基础操作(如输出内容、读取输入、处理参数等)。下面介绍个人学习中常用的几个命令。

4.2.1 echo:输出内容到终端*

echo 是最常用的内置命令,用于在终端打印文本,支持通过选项控制输出格式。

选项作用说明
-n输出内容后不自动换行
-e解析字符串中的转义字符(如下表)

常用转义字符(需配合 -e 使用):

转义字符作用说明
\n换行
\t制表符(Tab 键)
\b退格(删除前一个字符)

示例验证

# 1. -n 选项:不换行输出
[bq@shell ~]$ echo -n "bq "; echo "laowang"  # 第一个 echo 不换行,第二个 echo 换行
bq laowang  # 结果在同一行# 2. -e 解析 \n(换行)
[bq@shell ~]$ echo -e "bq\nlaowang"  # \n 表示换行
bq
laowang  # 分两行输出# 3. -e 解析 \t(制表符)
[bq@shell ~]$ echo -e "bq\tlaowang"  # \t 表示 Tab 缩进
bq	laowang  # 中间有一个 Tab 空格# 4. -e 解析 \b(退格)
[bq@shell ~]$ echo -e "1\b23"  # \b 删除前面的 "1"
23  # 结果只剩 "23"[bq@shell ~]$ echo -e "123\b"  # \b 后面没有字符,无法删除
123  # 仍输出 "123"[bq@shell ~]$ echo -ne "123\b"; echo "haha"  # -n 不换行,\b 删除 "3",再输出 "haha"
12haha  # "123" 变成 "12",加上 "haha" 就是 "12haha"
4.2.2 read:从终端读取输入

read 用于从用户输入中读取内容,并保存到变量中,常用于脚本中获取用户交互信息。

选项作用说明
-p显示提示信息(提示用户输入)
-s输入内容不显示(适用于密码)

示例验证

# 1. 基本用法:读取输入并打印
[bq@shell ~]$ cat read.sh 
#!/bin/sh
read -p "输入你想要说的话:" str  # -p 显示提示,输入内容保存到 str 变量
echo "你想要说的话是:$str"  # 打印变量内容# 执行脚本
[bq@shell ~]$ bash read.sh 
输入你想要说的话:hello world  # 输入内容
你想要说的话是:hello world  # 输出变量值# 2. -s 选项:隐藏输入(适合密码)
[bq@shell ~]$ read -s -p "请设置用户密码: " password  # -s 隐藏输入
请设置用户密码:  # 输入时不显示内容
[bq@shell ~]$ echo $password  # 验证输入的内容
redhat  # 正确输出输入的密码
4.2.3 exec:替换当前进程执行命令

exec 会用新的命令替换当前 Shell 进程(不创建子进程),新命令执行结束后,当前 Shell 也会终止。它也可以用于重定向输入输出。

示例 1:替换当前进程

# 切换到 root 用户,查看当前 Shell 的 PID
[root@shell ~]# ps $$  # $$ 是当前进程 PIDPID TTY      STAT   TIME COMMAND1741 pts/0    S      0:00 -bash  # 当前 Shell 的 PID 是 1741# 用 exec 执行 sleep 10(替换当前进程)
[root@shell ~]# exec sleep 10  # 当前进程(1741)变成 sleep 进程# 在另一个窗口查看 PID 1741 的进程
[bq@shell ~]$ ps 1741PID TTY      STAT   TIME COMMAND1741 pts/0    S+     0:00 sleep 10  # 确实替换成了 sleep# 10秒后 sleep 结束,当前 Shell 也终止,自动返回普通用户
[bq@shell ~]$ 

示例 2:重定向输入并读取文件 exec < 文件名 可以将脚本的标准输入重定向到文件,配合 read 可读取文件内容:

[bq@shell ~]$ cat exec.sh 
#!/bin/bash# 生成一个包含 1-5 的文件
seq 5 > /tmp/seq.log  # seq 5 输出 1-5,保存到 /tmp/seq.log# 将标准输入重定向到 /tmp/seq.log
exec < /tmp/seq.log  # 后续 read 命令会从这个文件读取内容# 循环读取文件内容并打印
while read line  # read 从标准输入(即文件)读取一行,保存到 line
doecho $line  # 打印读取的内容
done# 执行脚本,输出文件内容
[bq@shell ~]$ bash exec.sh
1
2
3
4
5

4.3 Shell 变量子串:截取和处理变量内容

变量子串是对变量内容进行 “截取、替换、删除” 等操作的语法,类似于字符串处理函数,能帮我们快速处理变量中的内容。

4.3.1 常用变量子串语法
语法格式作用说明
${parameter}返回变量 parameter 的内容(最基础的变量引用)
${#parameter}返回变量内容的长度(按字符计算,速度最快)
${parameter/pattern/string}string 替换变量中第一个匹配 pattern 的子串
${parameter//pattern/string}string 替换变量中所有匹配 pattern 的子串
4.3.2 变量子串实践示例

实验准备:定义一个测试变量 str="abc123abc123"(后续示例均基于此变量)。

[bq@shell ~]$ str="abc123abc123"

1. ${parameter}:引用变量内容 最基础的用法,直接返回变量的值:

[bq@shell ~]$ echo ${str}
abc123abc123  # 输出变量 str 的内容

2. ${#parameter}:获取变量长度 快速计算变量内容的字符个数(比其他方法更高效):

[bq@shell ~]$ echo ${#str}
12  # "abc123abc123" 共12个字符# 其他计算长度的方法(效率较低,了解即可)
[bq@shell ~]$ echo ${str} | wc -L  # wc -L 统计最长行的长度
12
[bq@shell ~]$ expr length "${str}"  # expr 工具计算长度
12
[bq@shell ~]$ echo "$str" | awk '{ print length($0)}'  # awk 计算长度
12

3. 替换子串:${parameter/pattern/string}${parameter//pattern/string}

  • /:只替换第一个匹配的子串
  • //:替换所有匹配的子串
# 只替换第一个 "abc" 为 "def"
[bq@shell ~]$ echo ${str/abc/def}
def123abc123  # 第一个 "abc" 被替换# 替换所有 "abc" 为 "def"
[bq@shell ~]$ echo ${str//abc/def}
def123def123  # 两个 "abc" 都被替换
4.3.3 实验应用案例

案例 1:批量修改文件名中的年份

# 创建一个测试文件
[bq@shell ~]$ touch stu-202212-snap.jpg
[bq@shell ~]$ ls stu-*
stu-202212-snap.jpg  # 原文件名# 用变量子串替换年份(2022→2021)
[bq@shell ~]$ file="stu-202212-snap.jpg"
[bq@shell ~]$ mv $file ${file/2022/2021}  # 替换第一个 2022 为 2021# 查看修改结果
[bq@shell ~]$ ls stu-*
stu-202112-snap.jpg  # 年份已修改

案例 2:删除文件名中的特定字符串

# 创建一个测试文件
[bq@shell ~]$ touch stu-202212-snap.jpg
[bq@shell ~]$ ls stu-*
stu-202212-snap.jpg  # 原文件名# 用变量子串删除 "-snap"
[bq@shell ~]$ file="stu-202212-snap.jpg"
[bq@shell ~]$ mv $file ${file/-snap/}  # 用空字符串替换 "-snap"# 查看修改结果
[bq@shell ~]$ ls stu-*
stu-202212.jpg  # "-snap" 已删除

如涉及版权问题,请联系作者处理!!!!

http://www.dtcms.com/a/343451.html

相关文章:

  • 加速你的故障排查:使用 Elasticsearch 构建家电手册的 RAG 应用
  • 如何实现文档处理全流程自动化?
  • 如何在日常开发中高效使用 Copilot
  • 无人机高科技,翱翔未来新天地
  • 对比学习与先验知识引导的特征提取网络在胶质瘤高风险复发区域预测中的应用|文献速递-深度学习人工智能医疗图像
  • GS-IR:3D 高斯喷溅用于逆向渲染
  • 2025年08月21日Github流行趋势
  • AI动画剧本、脚本、分镜头生成提示词
  • 【Flutter】Container设置对齐方式会填满父组件剩余空间
  • 【机器学习 / 深度学习】基础教程
  • PyTorch数据处理工具箱(可视化工具)
  • 嵌入式学习---(网络编程)
  • burpsuite2022.11激活步骤【超详细】
  • [系统架构设计师]通信系统架构设计理论与实践(十七)
  • anaconda+python+pycharm+mysql
  • 项目1总结其三(图片上传功能)
  • 站长导航网站,网址导航网站大全,网址导航网站合集,网址导航网址目录,网址导航网站推荐,欢迎提交收录
  • ICMP 协议分析
  • 从零开发Java坦克大战Ⅱ (下)-- 从单机到联机(完整架构功能实现)
  • PostgreSQL15——管理表空间
  • 基于Matlab的饮料满瓶检测图像处理
  • 宝塔面板深度解析:从快速部署到高效运维的全流程指南
  • 联想电脑使用U盘装机时,开机按F12时无法显示USB设备启动方式
  • 【python】python测试用例模板
  • 智能制造——解读46页大型集团企业MOM系统解决方案【附全文阅读】
  • 同为科技(TOWE)桌面PDU产品系列全方位解读
  • springboot 启动后get请求任意接口地址会跳到登录页
  • Vue.js 中使用 Highcharts 构建响应式图表 - 综合指南
  • unity中实现机械臂自主运动
  • almalinux9.6系统:k8s可选组件安装(2)