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

《Shell 大道:筑基篇(上)—— 神念控流程,函数成符阵》

文章目录

  • 前言
  • 一、流程控制
    • 1.1 `if …else`语句
      • 1.1.1 单支
      • 1.1.2 双支
      • 1.1.3 多支
      • 1.1.4 拓展案例
    • 1.2 `for` 循环
    • 1.3 `while` 循环
    • 1.4 `case` 语句
  • 二、函数
    • 2.1 定义与调用
    • 2.2 参数与返回值
    • 2.3 函数的高级用法
      • 2.3.1 函数的嵌套调用
      • 2.3.2 函数参数的默认值设置
      • 2.3.3 传递数组作为参数
  • 三、数组
    • 3.1 定义与访问
    • 3.2 遍历数组
  • 四、文件包含source
    • 4.1 语法
    • 4.2 示例
    • 4.3 实际环境用法
  • 总结


前言

【筑基初阶,符阵奠基】
道友既已练气圆满,气海充盈,当褪去 “单一气劲(命令)” 的练气桎梏,迈入以神念(逻辑)驭术的筑基之境。练气期,汝借终端辟紫府、凭变量存真气,仅能完成基础灵气调度;而筑基初阶,需学会以 “流程控制” 为脉络,以 “函数” 为符篆,将零散气劲编织成环环相扣的符阵(脚本)。

本篇将传汝两大筑基核心秘术:其一为 “流程控制” 心法,教汝以if-else断符阵走向、for/while驱灵气循环、case辨参数分支,让符阵依序而行、不偏不倚;其二为 “函数化符” 之法,可将重复术法凝为一枚专属符篆,召之即来、用之即去,大幅精简符阵结构。此二术乃筑基根基,练至大成,可让汝初步构建有序、高效的符阵,为后续 “灵气流转” 深造打下基础。


一、流程控制

1.1 if …else语句

1.1.1 单支

if 命令; then命令..
fi[ -d /etc ] && [ -r /etc ] && echo "true"
#因为&&先执行其前面的,如果前面正确运行即为1,则执行后面。
#所以&&可以当做单支if的一种写法

执行机制:判断一次,仅有一个结果

  • 结果为true,执行命令
  • 结果为flase,不执行命令

在 Shell 中,if 后面跟的命令必然会被执行,这是由 Shell 的语法规则决定的。

if 语句的工作原理是:

  1. 执行其后的命令
  2. 根据命令的退出状态码(0 表示成功,非 0 表示失败)来决定执行哪个分支

这就是为什么 if 后面的命令总会被执行 —— Shell 需要通过执行命令来获取其退出状态码,才能进行条件判断。

1.1.2 双支

if 命令; then# 命令执行成功(退出状态码为0)时执行的操作
else# 命令执行失败(退出状态码非0)时执行的操作
fi

shell中的命令状态码“0”为真,可以执行下一步判定。

#!bin/bash
if [ $UID -eq 0 ]; thenecho "当前登录用户是管理员"
elseecho "当前登录用户不是管理员"
fi

在这里插入图片描述

在if后跟命令,将命令的输出结果

#!/bin/bash
read -p "输入目录" dir
if ls $dir &> /dev/null; then
echo "有目录"
else
echo "无目录"
fi

在这里插入图片描述

1.1.3 多支

#!/bin/bash
read -e -p "输入文件路径:" file
if [ -e $file ]; thenif [ -d  $file ]; thenecho "路径指向的是目录"elif [ -f $file ]; thenecho "路径指向的是文件"elif [ -b $file ]; thenecho "路径指向的是块设备文件"elseecho "啥也不是"fi
elseecho "不是有效路径"
fi

在这里插入图片描述

1.1.4 拓展案例

自动安装httpd服务

#!/bin/bash
if netstat -antulp | grep ":80" &> /dev/null; thenecho "web服务已运行!"
elseif rpm -qa httpd &> /dev/null; thenecho "未安装httpd正在安装..."yum install -y httpd &> /dev/nullif [ $? -eq 0 ]; thensystemctl start httpdsystemctl enable httpd &> /dev/nullecho "已安装完成httpd服务,并启动和开机自启httpd"elseecho "安装httpd服务失败,请稍后自行安装..."fielseecho "正在启动http服务..."systemctl restart httpdecho "http服务已启动"fi
fi

在这里插入图片描述

自动获取并判断时间段

#!/bin/bash
#1.获取时间变量
time=$(date +%H)
#2.判断早上时间段
if (( time >= 6 && time <= 10  ));thenecho "早上$time 点"
#3.判断中午时间段
elif (( time >= 10 && time <= 14  ));thenecho "中午$time 点"#4.判断下午时间段
elif (( time >= 14 && time <= 18  ));thenecho "下午$time 点"#5.判断晚上时间段
elif (( time >= 18 && time <= 24  ));thenecho "晚上$time 点"
elseecho "凌晨$time 点"
fi

在这里插入图片描述

1.2 for 循环

for 变量名 in 列表; do# 循环体:对每个变量值执行的操作命令1命令2...
done
  • 变量名:用于临时存储列表中的每个元素(通常用i、item等)
  • 列表:要遍历的值(可以是直接列出的值、文件名、命令输出等)
  • do...done:包裹循环执行的命令
#C 语言风格的 for 循环
#!/bin/bash
for ((i=0; i<5; i++)); doecho $i
done
#遍历直接指定的列表
#!/bin/bash
for animal in cat dog elephant; doecho $animal
done

在这里插入图片描述

#for循环中进行操作
#!/bin/bash
count=0
for((i=1;i<=10;i++))
do
count=$(($count+$i))
done
echo "1加到10的结果为" $count

在这里插入图片描述

#!/bin/bashread -p "请输入你要探测的网段(格式如192.168.10):" network
#定义网段
#network=192.168.10echo "开始扫描${network}.0/24网段.."
echo "=============================="
>/root/ip1.txt
>/root/ip2.txtfor((i=0;i<255;i++));do{IP=${network}.${i}if ping -c 2 -i 0.2 -W 2 $IP &>/dev/null;thenecho "$IP ping通"echo $IP >> /root/ip1.txtelseecho "$IP ping不通"echo $IP >> /root/ip2.txtfi}&if ((i % 30 == 0 ));thenwaitfi
done
#后台进程(子进程)无法修改父进程的变量,当ping命令被放入{...}&内送至后台时无法再修改外部定义的计数变量,使用折中的方法,在外部生成一个可读写的临时文件,进行计数
suc=$(cat /root/ip1.txt | wc -l)
fai=$(cat /root/ip2.txt | wc -l)
wait
echo "==========================="
echo "扫描完成,共成功$suc 条,已将正确连通ip存储在/root/ip1.txt"
echo "扫描完成,共成功$fai 条,已将错误连通ip存储在/root/ip2.txt"

在这里插入图片描述
自动生成15位密码

#!/bin/bash
key="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
num=${#key}
for i in {1..15}
doindex=$[RANDOM%num]pass=$pass${key:$index:1}
doneecho "随机密码:$pass"

在这里插入图片描述
统计目录下的.log文件

#!/bin/bash
dir=/var/log
sum=0for i in $(ls -r "$dir"/*.log)
doif [ -f "$i" ];thenlet sum++echo "filename:$i"fi
done
echo "filenum is $sum"

1.3 while 循环

在 Shell 脚本中,while循环是一种常用的控制结构,用于重复执行一段代码,直到指定的条件变为假(非零退出状态)。

while [ 条件表达式 ]; do# 循环体:需要重复执行的命令
done
  • 基础循环
    输入对应字符后退出
#!/bin/bash
count=0
while [ "$y" != "yes" -a "$y" != "YES" ]
doecho "请输入yes/YES"read yif (( count < 10 ));theny=""echo "yes都不会打?"((count++))fi
done
echo "你做到了!"

在这里插入图片描述

  • 类似for循环的用法
    定义一个值,用值得大小作为循环结束的条件
 #!/bin/bash
#while循环的第二种方式:计算10以内数值的累加
count=0 # 记录累加值结果
num=1 # 循环初始值
while((num<=10))
do
#计算累加值的和count=$[$count+$num]
#((num++))
#使用let命令,计算变量++let num++ # 修改循环条件中的值
done
echo "10以内数值的累加和:${count}";

在这里插入图片描述

  • 死循环
#!/bin/bash
while true
doecho "请输入字符串:"read yif [ "$y" == "yes" ]; then#以状态码0进行退出,可以使用“#?”在外部获取状态码exit 0fi
done

在这里插入图片描述

不要使用下面的方法来自启linux系统中的文件,这会导致系统的额外开销,如果需要自动重启,systemd可以配置。

#!/bin/bash
while true
dowhile ps -aux | grep httpd | grep -v grep &> /dev/nulldosleep 10donesystemctl restart httpdecho "httpd关闭,已重启..."
done

在这里插入图片描述

1.4 case 语句

在 Shell 脚本中,case 语句用于多分支条件判断,类似于其他编程语言中的 switch-case 结构,适合处理多个固定值的条件判断场景。

case 变量 in模式1)命令1;;模式2)命令2;;模式3|模式4)  # 多个模式用 | 分隔(逻辑或)命令3;;*)  # 默认匹配,匹配所有未被前面模式匹配的情况默认命令;;
esac
  • 关键说明

    • 变量:通常是一个字符串或变量值,会与后续的模式进行匹配模式
    • 可以是具体的字符串(如 “start”、“stop”)
    • 可以包含通配符(* 匹配任意字符,? 匹配单个字符,[abc] 匹配括号中的任意一个字符)
    • 多个模式可用 | 分隔,表示 “或者” 的关系
    • 终止符:每个模式对应的命令块必须以 ;; 结束
    • 默认匹配:*) 用于匹配所有未被前面模式匹配的情况,类似 default
  • 示例

#!/bin/bash
case $1 in"start")systemctl start httpdecho "启动http服务";;"stop")systemctl stop httpdecho "停止http服务";;"restart")systemctl stop httpdsystemctl start httpdecho "重启http服务";;*)echo "无效参数";;
esac

在这里插入图片描述

#!/bin/bash
read -p "选择要查看的硬件的资源使用情况 1 cup 2 磁盘 3 内存 4退出" numcase $num in
"1")echo "正在查看cpu使用情况................."#-b批量处理模式:不以交互模式处理#n1:只在top上运行一次,生成一次结果集#top -bn1 | grep "Cpu(s)"
;;"2")echo "正在查看磁盘使用情况................."df -h
;;"3")echo "正在查看内存使用情况................."free -h
;;"4")echo "退出程序"exit 0
;;*)echo "输入无效"
;;
esac

在这里插入图片描述


二、函数

2.1 定义与调用

在 Shell 脚本中,函数(Function) 是一段可重复调用的代码块,用于封装特定功能、简化脚本结构、提高代码复用性和可维护性。它类似其他编程语言中的 “子程序” 或 “方法”,能让脚本逻辑更清晰,避免重复编写相同代码。

function 函数名字 ()
{
程序段;
[return int;]
}

基础示例:

#!/bin/bashsayHello()
{echo "你好"echo "Hello"
}sayHello

在这里插入图片描述

2.2 参数与返回值

在 Shell 中,调用函数时可以向其传递参数。在函数体内部, 通过 $n 的形式来获取参数的值,例如, $1 表示第一个参数, $2 表示第二个参数…注意, 当 n>=10时,需要使用${n} 来获取参数。

而返回值,可以使用$()来获取函数返回的输出字符串,或者用$?来获得return的状态码。

示例:

read -p "number1:" num1
read -p "number2:" num2sum1(){local sum=$(($1+$2))echo $sumreturn 0
}sum2(){local sum=$(($1+$2))echo "sum:$sum"return 1
}sum3(){local sum=$(($1+$2))echo "wwww"return 2
}
sum4(){echo $(($1+$2))return 3
}
sum1=$(sum1 $num1 num2)
sumR1=$?
sum2=$(sum2 $num1 num2)
sumR2=$?
sum3=$(sum3 $num1 num2)
sumR3=$?
sum4=$(sum4 $num1 num2)
sumR4=$?
echo "$sum1:$sumR1"
echo "$sum2:$sumR2"
echo "$sum3:$sumR3"
echo "$sum4:$sumR4"

在这里插入图片描述

2.3 函数的高级用法

2.3.1 函数的嵌套调用

Shell 函数支持嵌套(函数内部调用其他函数,甚至自身,即递归)。

#!/bin/bash# 递归函数:计算 n 的阶乘(n! = n * (n-1) * ... * 1)
factorial() {local n=$1if [ $n -eq 1 ]; thenecho 1  # 基线条件:1! = 1else# 递归调用:n! = n * (n-1)!local prev=$(factorial $((n-1)))echo $((n * prev))fi
}# 调用递归函数
result=$(factorial 5)
echo "5! = $result"  # 输出 120

2.3.2 函数参数的默认值设置

Shell 函数不直接支持 “默认参数”,但可通过判断参数是否为空来模拟:

#!/bin/bash# 函数:输出问候语,默认问候 "Guest"
greet() {# 若 $1 为空,则使用默认值 "Guest"local name=${1:-"Guest"}echo "Hello, $name!"
}# 调用函数(无参数,使用默认值)
greet  # 输出 "Hello, Guest!"# 调用函数(传递参数)
greet "Alice"  # 输出 "Hello, Alice!"

2.3.3 传递数组作为参数

若需传递数组给函数,需将数组展开为单个参数,再在函数内重新组合为数组:若需传递数组给函数,需将数组展开为单个参数,再在函数内重新组合为数组:

#!/bin/bash# 函数:计算数组所有元素的和
sum_array() {local arr=("$@")  # 将所有参数重新组合为数组local total=0for num in "${arr[@]}"; dototal=$((total + num))doneecho $total
}# 定义数组
numbers=(1 3 5 7 9)# 调用函数:展开数组为参数(${numbers[@]})
total_sum=$(sum_array "${numbers[@]}")
echo "数组总和:$total_sum"  # 输出 25

三、数组

3.1 定义与访问

Bash Shell 只支持一维数组(不支持多维数组),初始化时不需要定义数组大小。Shell 数组用括号来表示,元素用"空格"符号分割开。

array_name=(value1 value2 value3 ... valueN)
arr=(A B C d 123 2)
echo ${arr[0]}     # 输出:A
echo ${arr[@]}     # 输出所有元素
echo ${#arr[@]}    # 输出数组长度

在这里插入图片描述

也可以使用以下方法创建

array_name=([0]=value1 [1]=value2 [2]value3 ... [N-1]=valueN)array_name[0]=value1
array_name[1]=value2num=([1]=123 [3]=222)
num=([1]=123 qqq [5]=12)

在这里插入图片描述
在这里插入图片描述

3.2 遍历数组

读取数组元素值的一般格式是:

${array_name[index]}
#index 是指数组的索引,从0开始

使用for循环可以遍历数组:

for item in "${arr[@]}"; do echo $item
done
for item in "${arr[*]}"; doecho $item
done

在这里插入图片描述

#!/bin/bash
my_arr=(AA BB CC) #定义数组
my_arr_num=${#my_arr[*]} #获取数组的长度
for((i=0;i<my_arr_num;i++));
do
echo ${my_arr[$i]}
done

在这里插入图片描述


四、文件包含source

在一个Shell程序中可以指定包含外部的其他Shell脚本程序。这样可以很方
便的封装一些公用的代码作为一个独立的文件。

4.1 语法

有两种方法在一个脚本中引入另一个脚本:

. 空格 filename # 注意点号"."和文件名中间有一空格
source filename
. /etc/config.sh
source /etc/config.sh  

4.2 示例

  • config.sh
    app_name="MyApp"
    
  • main.sh
    source /etc/config.sh
    echo "应用名:$app_name"
    

在这里插入图片描述

4.3 实际环境用法

脚本一:采集数据
脚本二:处理数据

#!/bin/bash
echo "user  cpu  memory"
echo "1 2 3"user=$(whoami)cpu=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}')
#awk默认用空格做分割
memory=$(free -h | awk '/Mem/ {print $3}')echo "$user $cpu $memory"
#!/bin/bash
. /root/test0901/6.sh | while read user cpu mem
doif [ "$user" = "user" ];thenecho "user cpu mem hostname date"continue#跳出循环fihostname=$(hostname)date=$(date +"%Y-%m-%d %H:%M:%S")echo "$user $cpu $mem $hostname $date"
done

总结

【筑基初成,符阵有序】
恭喜道友!筑基初阶神通已修习得成!

此刻,汝之神念已能自如驾驭流程控制:if-else可依条件定符阵分支,无论是判断用户身份、校验文件路径,还是自动化安装服务,皆能精准决策;for/while可驱动灵气循环,遍历数组、重复交互皆不在话下;case能快速辨识参数,简化服务启停类符阵的逻辑。更掌握了 “函数化符” 之术,可将重复代码凝为函数,调用随心,让符阵结构更简洁、维护更易。

至此,汝已从 “依样画符” 的炼气士,成长为能独立构建 “有序符阵” 的筑基修士,可应对日常自动化场景中的基础需求。然筑基之路未竟,上一篇《筑基篇(下)》,将授汝 “灵气流转” 之妙诀,掌控数据输入输出的走向,让符阵运转更灵活、无滞碍。待流控之术修成,方算筑基圆满,可向金丹之境迈进!

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

相关文章:

  • 机器学习——模型架构
  • ✝常用表格✝
  • 读《独角兽项目:数字化转型》
  • 【开题答辩全过程】以 基于微信小程序的校园二手物品交易平台的设计与实现为例,包含答辩的问题和答案
  • 分布式光伏模式怎么选?从 “凭经验” 到 “靠数据”,iSolarBP 帮你锁定最优解
  • 苹果WWDC25开发秘鉴:AI、空间计算与Swift 6的融合之道
  • 领码方案:低代码平台前端缓存与 IndexedDB 智能组件深度实战
  • GDAL 简介
  • FAST API部署和使用
  • java讲解自己对业务架构、数据架构、应用架构的理解
  • gh-pages部署github page项目
  • 【机器学习入门】5.1 线性回归基本形式——从“选西瓜”看懂线性模型的核心逻辑
  • A2A + MCP 的python实现的最小可运行骨架
  • duilib中CTextUI控件使用技巧与问题总结(CTextUI控件自适应文字宽度特性)
  • 五、练习2:Git分支操作
  • 四、操作系统
  • 腾讯混元翻译大模型Hunyuan-MT-7B:重塑跨语言沟通的技术革命
  • 2025年应届生求职加分指南:这些新兴技能路径让你脱颖而出
  • 电子电气架构 --- 智能电动车EEA电子电气架构(下)
  • 【LeetCode 热题 100】5. 最长回文子串——中心扩散法
  • Linux按键输入实验
  • (纯新手教学)计算机视觉(opencv)实战十一——轮廓近似(cv2.approxPolyDP)
  • Python OpenCV图像处理与深度学习:Python OpenCV特征检测入门
  • “人工智能+”时代的端侧AI:算力下沉与实时视频的新基座
  • crypto-whatkey(2025YC行业赛)
  • 【OpenFeign】基础使用
  • 移动端签名组件横屏实现
  • LeetCode199. 二叉树的右视图 - 解题思路与实现
  • [系统架构设计师]案例(二十四)
  • 纯代码实现登录页面的DIY