ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

devops-exercises 之 Shell Scripting 实战指南:从变量、条件到调试与自测

devops-exercises 之 Shell Scripting 实战指南:从变量、条件到调试与自测 文档教程DevOps运维【免费下载链接】devops-exercisesLinux, 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 Scripting 主题文档 为核心骨架系统梳理该主题下的 12 个循序渐进的 Shell 脚本练习Hello World、变量、条件、算术、循环、函数、参数解析、目录对比、主机探测等以及一组面向面试的 Shell 自测问答。读完本篇你将掌握 Bash 变量的定义与默认值技巧、条件与算术运算、for/while 循环、函数封装、参数处理与调试手段并能直接用仓库内的练习与答案文件进行动手验证。一、练习总览一条由浅入深的 Bash 学习路径Shell Scripting 主题 在仓库中组织了 12 个练习每个练习都由题目Exercise 独立答案Solution成对存放主题覆盖从变量到中间难度的完整语法面名称主题练习答案难度Hello World变量练习答案BasicBasic date变量练习答案BasicGreat Day变量练习答案BasicFactors算术练习答案BasicArgument Check条件练习答案BasicFiles SizeFor 循环练习答案BasicCount Chars输入 While 循环练习答案BasicSum函数练习答案BasicNumber of ArgumentsCase 语句练习答案BasicEmpty Files杂项练习答案BasicDirectories Comparison杂项练习答案BasicIts alive!杂项练习答案Intermediate注仓库中 exercises/shell/solutions 目录下还存在directories_comparison.md等早期历史版本文件与topics/shell下的正式版互为参照均可用于对比学习。二、变量Bash 脚本的第一课2.1 定义与输出变量变量是脚本的基础。第一个练习 hello_world.md 要求定义一个值为 Hello World 的变量并把它的值打印并重定向到文件amazing_output.txt其参考答案为 solutions/hello_world.md#!/usr/bin/env bash HW_STRHello World echo $HW_STR amazing_output.txt要点拆解变量赋值HW_STRHello World等号两边不能有空格。这也是 README 中故障排查一节的经典陷阱题——写成x 2会导致命令解析错误正确写法必须是x2#!/usr/bin/env bash是可移植的 Shebang 写法用env在PATH中定位 bash比硬编码#!/bin/bash更适应不同发行版是输出重定向将 stdout 写入文件覆盖写入若想追加可用。2.2 命令替换把命令输出存入变量basic_date.md 要求把当前日期写入the_date.txt答案见 solutions/basic_date.md#!/usr/bin/env bash echo $(date) the_date.txt这里的$(date)就是命令替换子 shell 执行date并把输出替换到该位置等效于先DATE$(date)再echo $DATE。命令替换与管道是现代 Shell 脚本最重要的两个粘合剂。2.3 位置参数与默认值README 的自测部分给出了几个高频考点打印脚本收到的第一个参数echo $1打印yay除非传入了参数此时打印该参数echo ${1:-yay}${1:-yay}是参数默认值展开当$1为空时使用yay。great_day.md 正是这一技巧的应用——默认打印 Today is a great day!若传入某天名称则打印 Today is 其答案 solutions/great_day.md 只用一行就完成了分支逻辑#!/usr/bin/env bash echo Today is ${1:-a great day!}注意题目明确无需校验参数是否为合法日期因此可以用最简单的默认值展开这也是练习设计刻意想让你掌握的写法。2.4 特殊变量速查README 的面试题中有一道说明每个命令的结果的开放式问题答案要点如下仓库未直接给出文字解答以下为 Bash 标准语义可用于自查echo $0当前脚本或 shell自身的名称echo $?上一条命令的退出码0 表示成功非 0 表示失败echo $$当前 shell 的进程 IDPIDecho $#传给脚本的位置参数个数echo $所有参数构成的数组每个参数独立$vs$*$是所有参数的数组$*是所有参数拼成的一个字符串。差异在处理含空格的参数时尤为明显遍历参数推荐使用$。2.5 读取用户输入从用户获取输入使用内建命令readread x # 等待用户输入存入变量 x结合-p可在同一行给出提示read -p Please insert your input: line。2.6 比较变量长度比较两个变量这里指位置参数的长度if [ ${#1} -ne ${#2} ]; then ... fi${#var}是取字符串长度的展开语法-ne是数值比较符不等。2.7 变量的作用域local 与全局README 给出一道考察局部变量的脚本输出题#!/usr/bin/env bash NINJA_TURTLEDonatello function the_best_ninja_turtle { local NINJA_TURTLEMichelangelo echo $NINJA_TURTLE } NINJA_TURTLERaphael the_best_ninja_turtle输出是Michelangelo。原因函数内部的local关键字声明了一个仅在该函数内有效的同名局部变量函数内echo读到的是局部值脚本全局变量先后被赋为 Donatello、Raphael但函数执行时不受其影响。这一考点在实际工程中提醒我们封装函数时应尽量用local避免污染全局命名空间。三、条件判断if、[[ ]]、正则与否定3.1 条件判断的基本形态README 要求解释条件判断并演示用法开放式问答。Bash 条件判断的两套核心语法单方括号[ ... ]POSIX 风格内部变量一般要加引号如[ $a $b ]双中括号[[ ... ]]Bash 扩展支持、||、正则~、通配符匹配推荐在现代 Bash 中使用。典型 if/elseif [[ $1 pizza ]]; then echo with pineapple? else echo I want pizza! fi3.2 条件取反取反用!前缀例如if ! [[ $1 ~ $re ]]; then echo not a match fi3.3 判断参数是否为数字README 给出的正则方案regex^[0-9]$ if [[ ${var//*.} ~ $regex ]]; then ...其中${var//*.}会先把变量按最后一个点之后的部分替换后再做正则匹配见下文子串一节而~是 Bash 3.0 的正则匹配操作符。3.4 实战Argument Checkargument_check.md 要求参数为pizza则打印with pineapple?否则打印I want pizza!。答案 solutions/argument_check.md 用单行与或短路实现#!/usr/bin/env bash [[ ${1} pizza ]] echo with pineapple? || echo I want pizza!这正是 README 杂项一节提到的bash 三元风格[[ 条件 ]] 真分支 || 假分支是 if/else 的紧凑等价写法。注意此写法依赖真分支命令成功退出这一前提若真分支本身失败会误触发假分支复杂场景仍应使用完整 if/else。四、算术运算与取模4.1 算术的两种主流写法README 给出两种方式$(( 1 2 )) # Bash 算术展开推荐 expr 1 2 # 外部命令POSIX 通用但性能较差、注意空格$(( ... ))内部支持 - * / %、、、**等完整 C 风格算术。注意在$(( ))中变量可省略$如$(( x 1 ))。4.2 判断某数是否有 4 作为因子if [ $(($1 % 4)) -eq 0 ]; then%是取模运算符余数为 0 说明$1能被 4 整除。4.3 实战Factors因子判断factors.md 要求数字有 2 作因子打印one factor有 3 作因子追加打印...actually two!两者都不是则打印原数字。答案 solutions/factors.md 展示了命令退出码即条件的高级技巧#!/usr/bin/env bash (( $1 % 2 )) || resone factor (( $1 % 3 )) || res...actually two! echo ${res:-$1}解读(( ... ))作为命令其退出码由表达式是否为 0 决定——(( 0 ))退出码为 1假(( 非0 ))退出码为 0真。因此(( $1 % 2 )) || resone factor表示若余数非 0不能被 2 整除条件真则短路不赋值若余数为 0能被 2 整除条件假则执行赋值。res...是字符串追加${res:-$1}在res为空时回退打印数字本身。这一解法同时训练了退出码语义、逻辑短路与默认值展开三个知识点。五、循环for 与 while5.1 循环的概念与种类README 要求说明什么是循环及熟悉的循环类型开放式问答。Bash 常用三种for i in 列表; do ...; done遍历列表/通配符/命令输出while 条件; do ...; done条件为真时反复执行until 条件; do ...; done条件为假时反复执行与 while 相反。5.2 实战Files Sizefor 循环files_size.md 要求打印当前路径下每个文件与目录的名称和大小且必须使用至少一个 for 循环。答案 solutions/files_size.md#!/usr/bin/env bash for i in $(ls -S1); do echo $i: $(du -sh $i | cut -f1) done拆解ls -S1按大小排序-S并每行一个-1du -sh $i输出人类可读的磁盘占用cut -f1截取第一列去掉制表符后的路径echo组合输出名称: 大小。注意$i用双引号包裹以兼容含空格的路径。5.3 实战Count Charswhile 循环 readcount_chars.md 要求持续读入用户输入直到空串并统计每行字符数且必须用 while 循环。答案 solutions/count_chars.md#!/usr/bin/env bash echo -n Please insert your input: while read line; do echo -n $line | wc -c echo -n Please insert your input: done要点while read line是 Bash 中最经典的行读取模式read读到 EOF用户输入空行并回车后输入流结束时返回非 0循环随之退出echo -n不输出尾随换行保证wc -c统计的是纯字符数而非多算一个换行符题目约束假设至少三行输入规避了边界歧义便于把注意力集中在循环与统计本身。六、函数与参数校验Sum 实战sum.md 要求脚本接收两个数字并打印它们的和先校验输入确为两个数字且必须使用函数。答案 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可学习点正则^[0-9]$匹配纯数字串! [[ ... ... ]]同时取反与组合构成只要有一个不是数字就退出exit 2以非 0 退出码标识错误2 是自定义错误码0 为成功function sum { ... }定义函数函数内部通过$1、$2接收调用者传入的参数与脚本参数独立函数调用sum $1 $2把脚本参数转发给函数。此处校验只允许正整数若要支持负数/小数需把正则扩展为^-?[0-9](\.[0-9])?$之类这也是面试中常被追问的边界条件。七、参数个数与 Case 语句Number of Argumentsnum_of_args.md 要求一个参数时打印Got it: argument value无参数打印Usage: ./program name argument多个参数打印hey hey...too many!。答案 solutions/num_of_args.md 展示了set -eu与case的组合#!/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 $要点$#是参数个数case $# in按个数分支set -eu-e使脚本在任一命令失败时立即退出对应 README 自测中如何让脚本在命令失败时停止的答案-u使引用未定义变量时报错退出main $把全部参数安全地传给主函数引号包裹避免参数含空格时被拆分用printf %s而非echo可避免echo对-n、-e等字符串的歧义解析注意题目要求多个参数打印 hey hey...too many!而参考答案对*)分支仅return 1未打印该文案——若按题目原意补齐可在该分支加printf %s\n hey hey...too many!。练习与答案允许存在差异这本身也是学习按需改进的素材。八、杂项实战文件清理、目录对比与主机探测8.1 Empty Files删除空文件empty_files.md 要求删除给定目录含嵌套下所有空文件。答案 solutions/empty_files.md#! /bin/bash for x in * do if [ -s $x ] then continue else rm -rf $x fi done要点[ -s $x ]为真表示文件存在且大小非 0非空continue跳过否则删除。需注意该答案只遍历当前目录顶层*若要覆盖嵌套目录可结合find如find $dir -type f -empty -delete同时工程上删除操作务必先 dry-run如ls/echo验证再执行。8.2 Directories Comparison比较两个目录directories_comparison.md 要求输出两个目录之间的任何差异答案 solutions/directories_comparison.md 给出了两种方案方案一先校验参数个数再做校验和对比#!/bin/bash if test $# -ne 2 then echo -e USAGE: ./dirdiff.sh directory1 directory2 exit 1 fi # check for the checksums. # If both the checksums same, then both directories are same if test ls -1 $1 | sort | md5sum | awk -F {print $1} ls -1 $2 | sort | md5sum | awk -F {print $1} then echo -e No difference between the 2 directories exit 0 fi diff -q $1 $2思路ls -1列目录项 →sort排序消除顺序差异 →md5sum生成校验和 →awk截取哈希值两个校验和相等即无差异否则用diff -q输出实际差异文件。方案二GNU find/diff 递归对比推荐diff --recursive directory1 directory2这是最简洁可靠的方案diff -r--recursive递归逐文件对比两个目录树既比较文件内容也反映新增/删除项。仓库中 exercises/shell/solutions 下另有一份历史版本的directories_comparison.md与本答案互为补充可对照阅读。8.3 Host Status探测主机存活host_status.md 要求判断给定主机是宕机还是存活答案 solutions/host_status.md#!/usr/bin/env bash SERVERIPIP Address NOTIFYEMAILtestexample.com ping -c 3 $SERVERIP /dev/null 21 if [ $? -ne 0 ] then # Use mailer here: mailx -s Server $SERVERIP is down -t $NOTIFYEMAIL /dev/null fi要点ping -c 3发送 3 个 ICMP 包 /dev/null 21同时丢弃 stdout 与 stderr只保留退出码$?取出上一条命令的退出码-ne 0表示 ping 失败主机不可达触发告警mailx -s ... -t $NOTIFYEMAIL /dev/null发送主题为服务器宕机的邮件-t指定收件人这是典型的健康检查 告警运维脚本雏形属于该练习集中唯一的 Intermediate 难度题生产环境中常把该逻辑放入 cron 周期执行或用更专业的监控系统替代。九、调试与故障排查9.1 如何调试 Shell 脚本README 给出的答案高度依赖所用语言对 Bash给脚本或解释器加-x参数如bash -x script.sh逐行打印展开后的命令与变量值这是最常用的跟踪手段再加-v可同时打印源码行传统但有效的办法在关键位置插入echo输出中间变量对 Python 脚本则常用pdb调试器README 也顺带提及说明作者将脚本理解为广义的自动化脚本。9.2 经典陷阱赋值空格README 的题目执行下面脚本得不到 2为什么x 2 echo $x答案必须写成x2。x 2会被解析为运行命令x参数和2导致command not found。等号两侧不允许空格是 Shell 变量赋值最经典的坑。9.3 结合仓库验证语法devops-exercises 自带一个 语法检查脚本 与对应的 单元测试用来扫描仓库内 Markdown 文档中嵌入的代码块可作为写完脚本后自动校验的参考思路此外仓库根目录的 count_questions.sh 是一个真实运行在仓库 CI 中的 Bash 脚本可用作把 Bash 用于仓库自动化的实际案例进行研读。十、子串操作按分隔符截取README 的 Substring 小节给出两个高频实用写法提取字符串中最后一个点之后的全部内容如从file.tar.gz得到gz${var//*.}${var//pattern/replacement}是全局替换展开此处替换串为空*.匹配从最左侧到最后一个点的最长前缀删掉后剩下的就是最后一段。注意该写法会把最后一个点之前的所有内容替换掉得到的是最后一个点之后的部分。提取字符串中最后一个点之前的内容如从file.tar.gz得到file.tar${var%.*}${var%pattern}删除最短匹配的后缀.*匹配从最后一个点开始的剩余部分删除后即为最后一个点之前。两者合起来是取文件名/后缀的经典组合也是判断数字那一题里${var//*.}的来源。十一、杂项技巧与最佳实践11.1 生成 8 位随机数shuf -i 9999999-99999999 -n 1shuf -i指定整数范围含端点7 位到 8 位-n 1取一个样本。若要保证恰好 8 位首位非 0使用10000000-99999999更严谨。另一种常见做法是$RANDOM或od 裁剪。11.2 Bash 最佳实践举例README 以开放式问题要求举例无标准答案典型实践包括每个脚本开头注释说明用途与运行方式对 Bash 脚本加set -e命令失败即退出或set -eu 未定义变量报错变量引用尽量加双引号$var防止路径含空格被拆分用local限定函数内变量作用域用bash -n script.sh做语法检查、shellcheck做静态 lint。11.3 三元运算符README 定义三元运算符是 if/else 的简短写法Bash 示例[[ $a 1 ]] byes, equal || bnope等价于if [[ $a 1 ]]; then byes, equal; else bnope; fi。再次提醒该写法依赖真分支执行成功这一隐含前提副作用型命令不适合。11.4 进程替换Process SubstitutionREADME 的题目diff (ls /tmp) (ls /var/tmp)这是进程替换( command )把命令输出暴露为一个伪文件描述符从而在无法直接使用管道|的场景命令不支持 STDIN或需要同时合并多个命令的输出把多路输出喂给另一个命令。上面的例子相当于把/tmp与/var/tmp两个目录列表做 diff。注意(...)是 Bash/Ksh 的进程替换语法Zsh 亦支持POSIX sh 不支持。11.5 用什么测试 Shell 脚本README 的答案batsBash Automated Testing System。bats 允许以类似测试框架的方式为 Bash 函数/脚本编写用例断言输出与退出码适合为本章 12 个练习的答案编写自动化回归测试。十二、自测问答精要面试向README 底部附有一组面试自测题除上文已穿插讲解的之外还有三条高价值结论值得单独提炼#!/bin/bash是什么它叫 Shebang。/bin/bash是 Linux 系统用户登录常用的默认 shell名为 Bourne-again shell 的缩写Bash 能执行绝大多数脚本特性丰富、语法完善、发展成熟因此使用广泛。脚本中某条命令失败时脚本默认会退出并停止运行吗取决于语言与设置。对 Bash 而言答案是否——默认会继续执行后续命令多数场景我们反而希望一失败即停止此时在脚本中加set -e即可。有了 Ansible、Puppet、Chef 等配置管理工具为什么还要用 Shell 脚本典型理由速度快、灵活所需模块在 CM 工具中不存在尽管多数 CM 提供 shell 模块可兜底交付给无法访问公网、未安装 Ansible 的客户环境时纯 Shell 脚本零依赖、开箱即用。这三条分别对应语法常识、默认行为与防御式编程、工具选型思维是面试中最常被追问的方向。十三、为什么在 DevOps 语境下坚持学 Bash结合 README 的选型问答与本仓库 README.md 的整体定位Linux、Jenkins、AWS、SRE、Docker、Python、Ansible、Git、Kubernetes、Terraform 等 DevOps 全栈主题的题库与练习集可以这样理解 Shell 的位置配置管理工具解决大规模、可重复、幂等的编排问题而 Bash 解决就地、快速、零依赖的即时自动化问题Kubernetes 的kubectl流水线、CI 脚本、日常运维巡检中Bash 依然是粘合一切的语言。把本主题 12 个练习逐个手写并运行再对照 Shell 主题 README 的自测题完成自查即构成一套从语法到工程习惯的完整 Bash 训练闭环。赞分享文档教程DevOps运维【免费下载链接】devops-exercisesLinux, 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 CI/CD 实战指南从面试自测到 Jenkins 流水线与 Kubernetes 部署devops exercises CI/CD 实战指南从面试自测到 Jenkins 流水线与 Kubernetes 部署 本篇指南以开源仓库 devops e文档教程DevOps运维Mapbox GL JS球形投影与3D地形沉浸式地图体验终极指南Mapbox GL JS球形投影与3D地形沉浸式地图体验终极指南 Mapbox GL JS 是一个基于 WebGL 和矢量瓦片的开源地图引擎它原生支持 球形文档教程DevOps运维devops-exercises Ansible 完全指南从核心概念自测到实战 Playbook 编写devops exercises Ansible 完全指南从核心概念自测到实战 Playbook 编写 本指南以 devops exercises 仓库中 t文档教程DevOps运维上一篇Lively时间触发壁纸根据时段自动切换不同壁纸下一篇Bootstrap Table 表头分组功能实现复杂表格结构展示创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表