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

Linux Shell 编程

一、Shell 基础概念

1. 什么是 Shell?

Shell 是 Linux 内核与用户之间的交互接口,它接收用户输入的命令,解析后传递给内核执行,并将结果返回给用户。简单来说,Shell 是 “命令解释器”,也是一种编程语言(解释型语言,无需编译)。

2. 常见的 Shell 类型

Linux 系统中默认或常用的 Shell 有多种,不同 Shell 语法略有差异,编程常用 Bash(Bourne Again Shell)(大多数 Linux 发行版默认 Shell)。

Shell 类型特点与用途常见系统
Bash兼容 Bourne Shell,支持别名、函数、脚本编程CentOS、Ubuntu、Debian
Sh(Bourne)基础 Shell,功能简单,兼容性强早期 Unix、最小系统
Zsh增强型 Shell,支持自动补全、主题定制开发者常用(需手动安装)
Csh/Tcsh语法类似 C 语言,适合习惯 C 编程的用户少数 Unix 系统

查看当前系统默认 Shell:

echo $SHELL  # 输出示例:/bin/bash

查看系统支持的 Shell:

cat /etc/shells

二、Shell 脚本的创建与执行

1. 脚本文件的基本结构

Shell 脚本文件以 .sh 为后缀(非强制,但建议规范),核心结构包含 3 部分:

  1. Shebang(脚本解释器指定):第一行必须写 #!/bin/bash,指定脚本由 Bash 解释执行(若用其他 Shell,需改为对应路径,如 #!/bin/zsh)。
  2. 注释:以 # 开头的行(除 Shebang 外),用于说明脚本功能,提高可读性(单行注释,无多行注释,可通过 : '注释内容' 模拟多行注释)。
  3. 命令 / 代码:实现具体功能的 Shell 命令或语法逻辑。
示例:第一个 Shell 脚本(hello.sh)
#!/bin/bash
# 第一个 Shell 脚本:输出欢迎信息
echo "Hello, Linux Shell!"  # 打印字符串
whoami  # 输出当前登录用户
date    # 输出当前系统时间

2. 脚本的执行方式

执行脚本前需确保文件有 可执行权限x 权限),常见执行方式有 3 种:

执行方式命令格式特点
1. 绝对路径执行/home/user/hello.sh需指定脚本完整路径,依赖可执行权限
2. 相对路径执行./hello.sh(脚本在当前目录)需加 ./(避免与系统命令重名),依赖权限
3. 指定 Shell 执行bash hello.sh 或 sh hello.sh无需可执行权限(直接调用解释器)
权限设置命令
chmod +x hello.sh  # 给脚本添加可执行权限(所有用户)
chmod u+x hello.sh # 仅当前用户(所有者)添加可执行权限

三、Shell 变量与数据类型

Shell 是 弱类型语言,变量无需声明类型,直接赋值即可;变量默认存储字符串,需显式转换才能用于数值计算。

1. 变量的定义与使用

定义规则
  • 变量名由 字母、数字、下划线 组成,不能以数字开头。
  • 赋值时 等号两侧不能有空格(如 a=10 正确,a = 10 错误)。
  • 变量值含空格或特殊字符(如 $*)时,需用 双引号(") 或 单引号(') 包裹。
变量赋值与引用
#!/bin/bash
# 1. 普通变量(字符串/数值)
name="Alice"   # 双引号:允许变量嵌套(如引用其他变量)
age=25         # 数值默认按字符串存储
msg='Hello $name' # 单引号:完全原样输出($name 不会解析)# 2. 引用变量:用 $变量名 或 ${变量名}(避免歧义)
echo "Name: $name"       # 输出:Name: Alice
echo "Age: ${age}岁"     # 输出:Age: 25岁(${} 明确变量边界)
echo "Message: $msg"     # 输出:Message: Hello $name# 3. 系统环境变量(预定义,全大写)
echo "当前用户:$USER"   # 输出当前登录用户(如 root)
echo "当前目录:$PWD"    # 输出当前工作目录
echo "PATH路径:$PATH"   # 输出系统命令搜索路径

2. 变量的分类

按作用域和来源,Shell 变量分为 3 类:

变量类型定义方式作用域示例
局部变量用户在脚本 / 终端中直接定义仅当前 Shell 进程name="Bob"
环境变量export 变量名=值 或 /etc/profile当前 Shell 及子进程export PATH=$PATH:/opt
预定义变量Shell 内置,无需定义全局可用$?(上一条命令返回值)
常用预定义变量
变量含义示例场景
$0当前脚本的文件名脚本中打印自身路径:echo $0
$n脚本的第 n 个参数(n≥1,$1 是第一个参数)执行 ./test.sh 10 20$1=10
$#脚本接收的参数总数上例中 $#=2
$* / $@所有参数($* 合并为一个字符串,$@ 分开)遍历所有参数时用 $@
$?上一条命令的执行结果(0 = 成功,非 0 = 失败)判断命令是否执行成功
$$当前脚本的进程 ID(PID)记录脚本进程号
示例:参数处理脚本(param.sh)
#!/bin/bash
echo "脚本名:$0"
echo "第一个参数:$1"
echo "第二个参数:$2"
echo "参数总数:$#"
echo "所有参数:$@"# 遍历所有参数
echo "遍历参数:"
for param in $@
doecho "- $param"
done

执行脚本并传参:

./param.sh apple banana cherry
# 输出:
# 脚本名:./param.sh
# 第一个参数:apple
# 第二个参数:banana
# 参数总数:3
# 所有参数:apple banana cherry
# 遍历参数:
# - apple
# - banana
# - cherry

3. 数值计算

Shell 变量默认是字符串,需通过 算术扩展 或工具(exprbc)实现数值计算。

常用计算方式
  1. 算术扩展$((表达式)) 或 ${表达式}(支持 +-*/%(取余)、**(幂))。
  2. expr 命令expr 数值1 运算符 数值2(运算符两侧需空格,* 需转义为 \*)。
  3. bc 工具:支持浮点数计算(Shell 原生不支持浮点数)。
示例:数值计算
#!/bin/bash
a=10
b=3# 1. 算术扩展(整数计算)
sum=$((a + b))       # 13
diff=$((a - b))      # 7
mul=$((a * b))       # 30
div=$((a / b))       # 3(整数除法,舍去小数)
mod=$((a % b))       # 1(取余)
pow=$((a ** 2))      # 100(10的平方)echo "sum: $sum, diff: $diff, mul: $mul, div: $div, mod: $mod, pow: $pow"# 2. expr 命令
sum_expr=$(expr $a + $b)
mul_expr=$(expr $a \* $b) # * 需转义
echo "sum_expr: $sum_expr, mul_expr: $mul_expr"# 3. bc 工具(浮点数计算)
float_div=$(echo "scale=2; $a / $b" | bc) # scale=2 保留2位小数
echo "float_div: $float_div" # 输出:3.33

四、Shell 流程控制

流程控制是脚本逻辑的核心,包括 条件判断、循环、分支 三大类,语法与其他编程语言差异较大,需注意格式细节(如 thendo 的位置)。

1. 条件判断(if 语句)

语法结构

Shell 条件判断依赖 测试表达式(用 [ 表达式 ] 或 [[ 表达式 ]],注意括号两侧空格),判断结果为 true(0)时执行对应分支。

# 单分支
if [ 条件 ]; then命令1命令2
fi# 双分支(if-else)
if [ 条件 ]; then命令(条件成立)
else命令(条件不成立)
fi# 多分支(if-elif-else)
if [ 条件1 ]; then命令1
elif [ 条件2 ]; then命令2
else命令3
fi
常见测试表达式

条件判断主要针对 文件属性、数值大小、字符串比较,需注意运算符的差异:

测试类型运算符 / 表达式含义示例(判断为真)
文件属性-f 文件文件是否存在且为普通文件[ -f /etc/passwd ]
-d 目录目录是否存在[ -d /home ]
-r 文件文件是否存在且有读权限[ -r hello.sh ]
-x 文件文件是否存在且有可执行权限[ -x hello.sh ]
数值比较-eq(equal)等于[ $a -eq $b ](a=10, b=10)
-ne(not equal)不等于[ $a -ne $b ]
-gt(greater than)大于[ $a -gt $b ](a=10, b=3)
-lt(less than)小于[ $a -lt $b ]
-ge(greater or equal)大于等于[ $a -ge $b ]
-le(less or equal)小于等于[ $a -le $b ]
字符串比较== 或 =字符串相等[ "$name" == "Alice" ]
!=字符串不相等[ "$name" != "Bob" ]
-z 字符串字符串长度为 0(空字符串)[ -z "$empty_str" ]
-n 字符串字符串长度不为 0(非空)[ -n "$name" ]
示例:条件判断脚本(if_test.sh)
#!/bin/bash
read -p "请输入一个数字:" num  # read:读取用户输入,-p 显示提示信息# 判断输入是否为数字(用正则表达式,[[ 支持正则 ]])
if [[ $num =~ ^[0-9]+$ ]]; thenecho "你输入的是数字:$num"# 数值比较if [ $num -gt 100 ]; thenecho "该数字大于100"elif [ $num -eq 100 ]; thenecho "该数字等于100"elseecho "该数字小于100"fi
elseecho "错误:你输入的不是有效数字!"
fi

2. 分支选择(case 语句)

当需要判断一个变量与多个值匹配时,用 case 比 if-elif-else 更简洁,适合 “多值匹配” 场景(如菜单选择)。

语法结构
case $变量 in模式1)命令1;;  # 结束当前分支(类似其他语言的 break)模式2|模式3)  # 多个模式用 | 分隔(或关系)命令2;;*)  # 默认分支(所有不匹配的情况)命令3;;
esac  # case 的反向拼写,标志结束
示例:菜单脚本(case_menu.sh)
#!/bin/bash
echo "===== 菜单选择 ====="
echo "1. 查看当前目录"
echo "2. 查看系统时间"
echo "3. 查看当前用户"
echo "4. 退出"
read -p "请输入选择(1-4):" choicecase $choice in1)echo "当前目录内容:"ls -l;;2)echo "当前系统时间:"date;;3)echo "当前登录用户:"whoami;;4)echo "退出脚本,再见!"exit 0  # exit 0:正常退出(返回值0);;*)echo "错误:无效选择!"exit 1  # exit 1:异常退出(返回值非0);;
esac

3. 循环语句(for、while、until)

循环用于重复执行一系列命令,Shell 支持 for(遍历集合)、while(条件为真时循环)、until(条件为假时循环)三种循环。

(1)for 循环

主要用于 遍历列表(数组、参数、文件),语法有两种:

语法 1:遍历指定列表
for 变量 in 列表; do命令
done
语法 2:C 语言风格(数值范围循环)
for ((初始化; 条件; 增量)); do命令
done
示例:for 循环应用
#!/bin/bash
# 示例1:遍历字符串列表
echo "遍历水果列表:"
fruits="apple banana cherry"
for fruit in $fruits; doecho "- $fruit"
done# 示例2:遍历文件(当前目录下的 .sh 文件)
echo -e "\n当前目录的 Shell 脚本:"
for file in *.sh; doecho "- $file"
done# 示例3:C 风格循环(1到5)
echo -e "\nC 风格循环(1-5):"
for ((i=1; i<=5; i++)); doecho "i = $i"
done
(2)while 循环

条件为真时持续循环(类似其他语言的 while),适合 “不确定循环次数,依赖条件终止” 的场景(如读取文件行、等待用户输入)。

语法
while [ 条件 ]; do命令
done
示例 :读取文件行(逐行处理文件内容)
#!/bin/bash
# 读取 test.txt 文件的每一行(假设文件已存在)
echo "读取 test.txt 内容:"
while read line; do  # read line:每次读取一行存入 line 变量echo "Line: $line"
done < test.txt  # < test.txt:将文件作为 while 循环的
http://www.dtcms.com/a/357770.html

相关文章:

  • 淘宝商品评论接口技术实现:从评论获取到情感分析全流程方案
  • SQL知识
  • 序列容器(vector,deque,list)
  • 4x12G-SDI(四链接12G-SDI)
  • PCIe 6.0 TLP结构解析:深入理解事务层数据包的设计与实现
  • Windows Command Line Windows 命令行
  • 【RAG Agent实战】告别“单线程”RAG:用查询理解与LangGraph构建能处理复杂意图的高级代理
  • ros2--action/动作--接口
  • 2024年12月 Python(四级)真题解析#中国电子学会#全国青少年软件编程等级考试
  • 中科米堆CASAIM五金配件三维扫描测量尺寸形位公差
  • MySQL 中如果发生死锁应该如何解决?
  • OpenAI宣布正式推出Realtime API
  • ADC模数转换
  • Set和Map
  • AI的“科学革命”:Karpathy吹响号角,从“经院哲学”走向“实验科学”
  • 【.net core】【NPOI】读取表格信息(处理合并行表格数据)
  • vscode里面可以批量放弃更改
  • Linux驱动异步通知机制详解
  • Labview邪修01:贪吃蛇
  • 【完整源码+数据集+部署教程】控制台缺陷检测系统源码和数据集:改进yolo11-repvit
  • IDEA编译报错:Error:(3, 28) java: 程序包com.alibaba.fastjson不存在
  • GPFS性能优化
  • zyplayer-doc:AI 驱动的智能知识库
  • LeetCode力扣-hot100系列(2)
  • MQTT高延迟通信优化指南
  • 解密企业数据安全:服务业加密软件的核心价值
  • POE供电是什么?
  • RAG教程5:多表示索引和ColBERT
  • 不一样的发票管理模式-发票识别+发票查验接口
  • 篮球API接口:技术如何革新体育数据体验