news 2026/10/2 0:13:03

devops-exercises 实战:用 Bash 函数与正则校验编写两数求和脚本

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
devops-exercises 实战:用 Bash 函数与正则校验编写两数求和脚本
  • 文档
  • 教程
  • DevOps
  • 运维

【免费下载链接】devops-exercises

Linux, Jenkins, AWS, SRE, Prometheus, Docker, Python, Ansible, Git, Kubernetes, Terraform, OpenStack, SQL, NoSQL, Azure, GCP, DNS, Elastic, Network, Virtualization. DevOps Interview Questions

项目地址:https://gitcode.com/GitHub_Trending/de/devops-exercises
点击查看免费下载

导读

本篇技术指南围绕 devops-exercises 仓库 Shell 脚本练习中的Sum(求和)题目展开,这是仓库中专门用于训练Bash 函数(Functions)这一主题的基础级练习。通过本文,你将掌握如何编写一个接受两个命令行参数、用正则表达式校验输入合法性、再通过自定义函数完成算术运算的完整 Bash 脚本,并了解仓库内其他 Shell 练习(如 Number of Arguments、Factors)所体现的 Bash 最佳实践,可直接用于日常自动化脚本开发与面试准备。

一、练习背景:题目要求与约束

Sum 练习位于仓库的 topics/shell/sum.md,对应的完整参考答案见 topics/shell/solutions/sum.md。在 topics/shell/README.md 的练习总表中,它被明确归类为:

  • 主题(Topic):Functions(函数)
  • 难度:Basic(基础)

题目目标(Objectives)

  1. 编写一个脚本,接收两个数字并打印它们的和;
  2. 确保输入有效(即确实从用户那里得到了两个数字);
  3. 通过运行脚本并传入两个数字作为参数来测试它。

约束(Constraints)

  1. 必须使用函数(Use functions)。

这是一道典型的“参数解析 + 输入校验 + 函数封装”组合题,麻雀虽小五脏俱全:它同时考察了 Bash 的位置参数($1、$2)、正则匹配(=~)、条件判断(if)、算术展开($(( )))以及函数定义与调用——这些都是日常 Shell 脚本中最常用的能力。

二、参考答案逐行拆解

题目要求使用函数,参考答案(topics/shell/solutions/sum.md)给出了一个完整可运行的脚本:

#!/usr/bin/env bash re='^[0-9]+$' if ! [[ $1 =~ $re && $2 =~ $re ]]; then echo "Oh no...I need two numbers" exit 2 fi function sum { echo $(( $1 + $2 )) } sum $1 $2

1. Shebang:#!/usr/bin/env bash

第一行使用#!/usr/bin/env bash而非硬编码的#!/bin/bash。env会在当前用户的PATH中查找bash,这提高了脚本在不同 Linux 发行版(bash 可能安装在/usr/bin、/bin或其他位置)之间的可移植性,是仓库内几乎所有练习脚本统一采用的写法(参见 topics/shell/solutions/hello_world.md 等)。

2. 定义正则:re='^[0-9]+$'

re='^[0-9]+$'

这里定义了一个扩展正则表达式(ERE):

  • ^锚定字符串开头;
  • [0-9]匹配一个十进制数字字符;
  • +表示前面的数字至少出现一次;
  • $锚定字符串结尾。

因此该模式只匹配“完全由一位或多位数字组成”的字符串,例如5、42、1024合法,而abc、3.14、-7、12x都不匹配。这一校验写法在 topics/shell/README.md 的“如何检查给定参数是否为数字”自测题中也有对应体现:regex='^[0-9]+$'。

注意:-7不会被判定为合法数字,因为-不在字符类[0-9]中。这是本题校验策略的一个边界,下文“改进方向”会专门讨论。

3. 输入校验:[[ $1 =~ $re && $2 =~ $re ]]

if ! [[ $1 =~ $re && $2 =~ $re ]]; then echo "Oh no...I need two numbers" exit 2 fi

这是整个脚本的“安全门”:

  • [[ ... ]]是 Bash 的扩展条件测试结构,其中=~运算符用于正则匹配(右侧为正则模式,左侧为被测试字符串);
  • &&在[[ ]]内部表示逻辑与,要求$1和$2同时都是纯数字才通过校验;
  • !对整个条件取反:只要有一个参数不是数字,条件即成立,进入错误分支;
  • 打印提示信息Oh no...I need two numbers后以退出码2结束脚本。

为什么用退出码 2?在 Unix/Linux 惯例中,退出码0表示成功,非零表示失败,而用具体的非零值区分错误类型是常见做法(例如1表示一般性错误、2表示参数或用法错误)。这里exit 2与许多标准命令行工具“用法错误返回 2”的约定一致,便于调用方在脚本或 CI 中根据退出码判断失败原因。仓库中 topics/shell/solutions/num_of_args.md 的参考答案也采用了类似的思路——参数数量不合法时return 1。

另外一个值得注意的细节:[[ $1 =~ $re ]]中$1没有加双引号。在[[ ]]内部这是安全的,因为[[ ]]不会做词法分割与路径名展开;但=~右侧的模式变量$re一旦被加引号就会变成字面量匹配(即把字符串^[0-9]+$当普通文本去比对),这是 Bash 正则匹配最容易踩的坑。本题通过把模式存入变量再引用,恰好规避了这个问题。

4. 定义函数:function sum { ... }

function sum { echo $(( $1 + $2 )) }
  • function sum是 Bash 中定义函数的两种语法之一(另一种是sum() { ... },两者等价);
  • 函数体内的$1、$2是函数的参数,而不是脚本的参数——调用sum $1 $2时,脚本的$1、$2会被“传参”给函数,函数内通过自身的$1、$2读取。这正是题目要求“使用函数”时函数与脚本参数分离的关键点;
  • $(( ... ))是 Bash 的算术展开(Arithmetic Expansion),$(( $1 + $2 ))会先做整数加法,再把结果作为字符串展开;
  • echo把计算结果打印到标准输出。

关于算术运算,topics/shell/README.md 的自测部分也给出了两种实现方式:$(( 1 + 2 ))和expr 1 + 2。参考答案选择了前者,因为它是 Bash 内建特性,无需启动外部进程,性能更好、语法更简洁。

5. 调用函数:sum $1 $2

脚本末尾调用函数,并把脚本的两个位置参数传入。此时函数内部计算$1 + $2并echo结果,脚本退出码为最后一个命令(echo)的退出码,即0(成功)。

三、完整运行与测试步骤

把参考答案保存为sum.sh后,按以下步骤在终端验证:

# 1. 赋予可执行权限 chmod +x sum.sh # 2. 正常用例:传入两个数字 ./sum.sh 3 5 # 输出:8 # 3. 大数字用例 ./sum.sh 100 200 # 输出:300 # 4. 非法输入:参数不是数字 ./sum.sh abc def # 输出:Oh no...I need two numbers # 退出码为 2(可通过 echo $? 查看) # 5. 非法输入:只传一个数字 ./sum.sh 3 # 输出:Oh no...I need two numbers($2 为空,空串不匹配正则)

题目目标第 3 条要求“运行脚本并传入两个数字作为参数进行测试”,以上用例完整覆盖了“合法输入”与“非法输入”两条路径。可以用echo $?验证:合法路径退出码为0,非法路径退出码为2,这说明脚本的校验逻辑真实生效。

四、从仓库其他练习看 Bash 最佳实践

Sum 练习虽然只有 15 行,但把它与仓库内同目录的其他 Shell 练习参考答案对照,可以提炼出一整套可复用的 Bash 工程化习惯:

1. 用set -eu提升脚本健壮性

topics/shell/solutions/num_of_args.md 的参考答案开头是:

#!/usr/bin/env bash set -eu main() { case $# in 0) printf "%s" "Usage: ./<program name> <argument>"; return 1 ;; 1) printf "%s" "Got it: $1"; return 0 ;; *) return 1 ;; esac } main "$@"

其中set -eu的含义是:-e让脚本在任一命令失败时立即退出,-u让脚本在引用未定义变量时直接报错。这与 topics/shell/README.md 自测题中“用set -e让 Bash 在特定命令失败时退出”的回答相互印证。它还展示了两个优秀习惯:

  • 把主逻辑封装进main()函数,再用main "$@"显式传入所有参数——"$@"是参数数组,"$*"是单个字符串,两者差异在 README 自测部分有专门解释;
  • 用case $#处理“零个 / 一个 / 多个参数”的分支,这与 Sum 脚本用exit 2表达用法错误的理念一脉相承。

如果把这一习惯移植到 Sum 脚本,可以写成set -u(配合$1直接引用时未传参会产生告警,此时正则校验分支恰好会拦截空参数),不过参考答案刻意保持最小化,只聚焦“函数 + 校验”两个考点。

2. 用(( ))做整数判断

topics/shell/solutions/factors.md 展示了另一条算术展开的用法:

#!/usr/bin/env bash (( $1 % 2 )) || res="one factor" (( $1 % 3 )) || res+="...actually two!" echo ${res:-$1}

(( ))是 Bash 的算术求值结构,表达式结果为0时返回退出码 1(假),非0时返回退出码 0(真),配合||可以实现紧凑的条件赋值;${res:-$1}则是参数展开的默认值语法(变量为空时用$1兜底)。这与 Sum 脚本中的$(( $1 + $2 ))同属算术展开家族,区别仅在于前者用于判断、后者用于计算。

3. 条件表达式的两种风格

topics/shell/solutions/argument_check.md 用一行实现了 if/else 的简写(Bash 中的“三元运算符”风格):

[[ ${1} == "pizza" ]] && echo "with pineapple?" || echo "I want pizza!"

而 Sum 脚本使用完整的多行if ! [[ ... ]]; then ... fi。两种风格各有适用场景:简单分支用&&/||更简洁,涉及exit、多语句或可读性优先时用完整if更清晰——本题因为有校验失败退出逻辑,参考答案选择了后者,是合理的取舍。

4. 交互式输入的替代方案

如果题目“从用户那里得到两个数字”不是指命令行参数,而是运行时输入,则可以使用read关键字(topics/shell/README.md 自测题:read x会等待用户输入并存入变量x)。topics/shell/solutions/count_chars.md 的while read line; do ... done就是交互式读取的完整示例。但本题明确要求“传递两个数字作为参数”(Objectives 第 3 条),因此参考答案采用$1/$2参数方案。

五、常见陷阱与扩展改进方向

理解了参考答案后,可以沿着几个方向继续深挖,这也是面试中常见的追问点:

  1. 负数与小数不支持:^[0-9]+$只能匹配非负整数。若需支持负数,可改为^-?[0-9]+$;若需支持小数或科学计数法,则需要更复杂的模式(如^-?[0-9]+(\.[0-9]+)?$),且$(( ))本身只支持整数运算,浮点需要改用awk、bc或printf等工具。

  2. 参数缺失时的表现:脚本要求两个参数,但若用户只传一个参数(如./sum.sh 3),$2为空串,正则匹配失败,脚本会走错误分支——行为是安全的。但若要给出更精确的提示(区分“参数数量不足”和“参数非数字”),可参考 topics/shell/solutions/num_of_args.md 先用$#检查参数个数,再做格式校验。

  3. 引用与引号:在[[ =~ ]]中右侧正则若被加引号会失去正则语义;在[ ](POSIX test)中则没有=~可用。日常调试时可以用bash -x sum.sh 3 5打开执行跟踪(topics/shell/README.md 自测部分明确推荐-x参数调试 Bash 脚本),观察每个命令的实际展开结果。

  4. 函数返回值与退出码:函数内echo输出到 stdout 是“返回计算结果”的常用手段;若函数需要表达“计算失败”,可以用return 非零并让调用方检查$?。参考 topics/shell/solutions/num_of_args.md 中main()对return 1/return 0的用法。

小结

Sum 是 devops-exercises 仓库 Shell 练习集中最精简、最聚焦的一道函数练习:它用 15 行代码串联起了 Shebang、正则校验、条件分支、算术展开、函数定义与调用、退出码六大 Bash 核心知识点。结合仓库中 topics/shell/solutions/num_of_args.md、topics/shell/solutions/factors.md、topics/shell/solutions/argument_check.md 等参考答案以及 topics/shell/README.md 的自测问答,你可以把这一小脚本扩展成一套稳定的“参数校验 + 函数封装 + 错误处理”模板,直接复用到日志清理、批量计算、部署脚本等真实运维场景中。

  • 文档
  • 教程
  • DevOps
  • 运维

【免费下载链接】devops-exercises

Linux, Jenkins, AWS, SRE, Prometheus, Docker, Python, Ansible, Git, Kubernetes, Terraform, OpenStack, SQL, NoSQL, Azure, GCP, DNS, Elastic, Network, Virtualization. DevOps Interview Questions

项目地址:https://gitcode.com/GitHub_Trending/de/devops-exercises
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/2 0:12:44

ESXi 6.7物理服务器启动盘制作全指南

1. 这不是普通装系统&#xff0c;是给物理服务器“打底”的关键一步你手头有一台闲置的旧服务器、一台二手Dell R720、或者刚淘来的HP ProLiant DL360&#xff0c;想把它变成一个稳定跑虚拟机的私有云平台——这时候&#xff0c;ESXi 6.7 就成了最务实的选择。它轻量、高效、资…

作者头像 李华
网站建设 2026/10/2 0:00:01

GPT API接入四要素:base_url配置、模型标识、倍率规划与稳定性兜底

前阵子帮团队梳理 AI 功能接入方案&#xff0c;发现好多项目卡住的地方居然不在提示词工程&#xff0c;也不在模型效果调优&#xff0c;而是最前面的接入配置。其实接入 GPT API 说穿了就四件事&#xff1a;API 地址、模型标识、倍率规划、稳定性兜底。把这几件事在动手前确认清…

作者头像 李华
网站建设 2026/10/1 23:59:38

hindsight 记忆框架实战:LLM Agent 记忆机制与 MCP 部署

1. 从 "hindsight" 这个词说起&#xff1a;为什么记忆是 Agent 最被低估的能力"hindsight" 这个词本身很有意思&#xff0c;字面意思是"后见之明"&#xff0c;也就是事后回头看才能看清的东西。把它作为项目标题&#xff0c;指向的其实是 LLM Ag…

作者头像 李华
网站建设 2026/10/1 23:59:29

TensorFlow 2024实战:从安装到图像分类部署

1. 为什么我现在还在谈TensorFlow&#xff1a;从项目说起 说到TensorFlow&#xff0c;很多人第一反应是&#xff1a;这框架是不是已经过气了&#xff1f;我最早接触TensorFlow是在2016年底&#xff0c;当时对着Session、placeholder折腾了整整一个周末才把一个线性回归跑通。后…

作者头像 李华
网站建设 2026/10/1 23:57:30

AI Engineering from Scratch:重建可验证、可审计的AI系统工程体系

1. 这不是“搭积木”&#xff0c;而是重建AI系统的底层施工逻辑很多人看到“AI Engineering from Scratch”第一反应是&#xff1a;不就是用LangChain搭个RAG&#xff0c;再调几个OpenAI API&#xff1f;——这恰恰是当前最危险的认知陷阱。我带过17个AI工程落地项目&#xff0…

作者头像 李华
网站建设 2026/10/1 23:56:15

Jev模型从申请密钥到接入Codex的全流程实操指南

最近后台和粉丝群里聊什么的都有&#xff0c;但频率最高的还是同一个名字&#xff1a;Jev。好几个读者直接把截图甩给我&#xff0c;问这东西到底靠不靠谱、怎么申请、是不是开源、能不能塞进 Codex 里当外挂用。说实话&#xff0c;这类"一夜爆火"的新模型我见了不少…

作者头像 李华