重生之我拿捏Linux——《三、shell脚本使用》

上一章咱们搞定了权限控制,这一章直接解锁 Linux 自动化的"核心技能"------Shell 脚本!不管是批量处理文件,还是定时执行系统任务,掌握 Shell 脚本都能让你从"重复敲命令"的困境中解放出来,真正实现"一次编写,多次复用"。今天就从语法基础到实战案例,带你吃透 Shell 脚本的用法!

一、bash语法

1. 脚本头部声明

  • 作用:指定脚本解释器,必须放在脚本第一行
  • 语法#!/bin/bash(表示使用bash解释器执行脚本,而非默认的sh

2. 变量

  • 定义变量名=值(等号前后无空格)例:name="Bash学习者"version=5.1
  • 使用$变量名${变量名}(加花括号避免歧义)例:echo "欢迎你,$name"echo "第${i}个元素"
  • 命令替换 :将命令结果赋值给变量,两种语法
    • 变量=$(命令)(推荐):current_dir=$(pwd)
    • 变量=命令(反引号):`date=`date +%F
  • 局部变量 :在函数内用local声明,仅函数内有效例:local name=$1

3. 环境变量

  • 定义:系统预定义的变量,全大写字母,全局有效
  • 常用环境变量
    • $USER:当前用户名
    • $HOME:用户家目录
    • $PATH:可执行程序的搜索路径
    • $PWD:当前工作目录
    • $?:上一条命令的退出状态(0 为成功,非 0 为失败)

4. 位置参数

  • 定义 :脚本运行时传入的参数,用$n表示(n 为数字)
  • 常用参数变量
    • $0:脚本自身的文件名
    • $1~$9:第 1 到第 9 个参数(超过 9 个用${10}
    • $#:参数的总个数
    • $*/$@:所有参数($*将参数视为整体,$@视为独立个体)
    • $?:上一条命令的执行结果(0 成功,非 0 失败)

5. 条件判断

  • 基本语法

    bash

    复制代码
    if [ 条件表达式 ]; then
        命令
    elif [ 条件表达式 ]; then
        命令
    else
        命令
    fi

    (注意:[ ]前后必须有空格,条件表达式内部也要有空格)

  • 数值比较

    • -eq:等于([ 1 -eq 1 ]
    • -ne:不等于
    • -lt:小于(less than)
    • -gt:大于(greater than)
    • -le:小于等于
    • -ge:大于等于
  • 字符串比较

    • =:等于([ "a" = "b" ]
    • !=:不等于
    • -z:字符串长度为 0(空字符串)
    • -n:字符串长度非 0
  • 文件 / 目录判断

    • -f 文件名:是否为普通文件
    • -d 目录名:是否为目录
    • -e 路径:路径是否存在
    • -r 路径:是否有读权限
    • -w 路径:是否有写权限
    • -x 路径:是否有执行权限

6. 循环结构

for 循环

  • 遍历列表

    bash

    复制代码
    for 变量 in 列表; do
        命令
    done

    例:for fruit in 苹果 香蕉 橙子; do echo $fruit; done

  • 遍历数组

    bash

    复制代码
    fruits=("苹果" "香蕉" "橙子")
    for fruit in "${fruits[@]}"; do  # @表示所有元素,加引号避免空格分割问题
        echo $fruit
    done
  • 数字范围

    bash

    复制代码
    for i in {1..5}; do  # 1到5的数字
        echo $i
    done

while 循环

  • 语法

    bash

    复制代码
    while [ 条件 ]; do
        命令
        (更新条件,避免死循环)
    done

    例:

    bash

    复制代码
    count=1
    while [ $count -le 3 ]; do
        echo $count
        count=$((count + 1))  # 数值自增
    done

7. 函数

  • 定义

    bash

    复制代码
    函数名() {
        命令
        [return 退出码]  # 可选,默认返回最后一条命令的状态
    }
  • 调用函数名 [参数]例:greet "Bash学习者"

  • 参数传递 :函数内用$1~$n接收参数(同位置参数)例:

    bash

    复制代码
    add() {
        echo $(( $1 + $2 ))  # 通过echo返回计算结果
    }
    result=$(add 10 20)  # 调用并获取结果
  • 返回值

    • echo输出结果(适合返回数据)
    • return返回退出码(0-255,适合判断成功 / 失败)

8. 输入输出重定向

  • 标准输出重定向

    • >:覆盖写入文件(echo "内容" > file.txt
    • >>:追加写入文件(echo "内容" >> file.txt
  • 标准错误重定向

    • 2>:覆盖写入错误信息(command 2> error.log
    • 2>>:追加写入错误信息
  • 合并输出与错误

    • &>:同时重定向输出和错误(command &> all.log

9. 管道(Pipe)

  • 语法命令1 | 命令2
    • 将命令 1 的输出作为命令 2 的输入例:ls -l | grep ".sh"筛选目录中.sh 文件)例:cat file.txt | wc -l(统计文件行数)

10. 数组

  • 定义数组名=(元素1 元素2 ...)例:colors=("红色" "绿色" "蓝色")

  • 访问元素${数组名[索引]}(索引从 0 开始)例:${colors[1]}(获取第二个元素 "绿色")

  • 所有元素${数组名[@]}${数组名[*]}例:echo "${colors[@]}"

  • 数组长度${#数组名[@]}例:echo "数组长度:${#colors[@]}"

11. 数值计算

  • 语法$(( 表达式 ))例:sum=$(( 10 + 20 ))count=$((count + 1))支持+-*/%(取余)等运算符

12. 注释

  • 单行注释:# 注释内容(脚本中除了#!/bin/bash外,#后的内容均为注释)

二、具体实例

1. 变量定义与使用

bash 复制代码
# 定义变量(等号前后无空格)
name="Alice"
age=30

# 使用变量($变量名 或 ${变量名})
echo "姓名:$name,年龄:${age}岁"  # 输出:姓名:Alice,年龄:30岁

# 命令替换(将命令结果存为变量)
current_time=$(date +"%H:%M:%S")  # 推荐用$()
echo "当前时间:$current_time"    # 输出:当前时间:15:30:45

# 变量拼接
prefix="file_"
suffix=".txt"
filename="${prefix}001${suffix}"
echo $filename  # 输出:file_001.txt

2. 环境变量与位置参数

bash 复制代码
# 环境变量(系统预定义)
echo "当前用户:$USER"       # 输出:当前用户:your_username
echo "家目录:$HOME"         # 输出:家目录:/home/your_username
echo "命令搜索路径:$PATH"   # 输出:一堆目录(用冒号分隔)

# 位置参数(运行脚本时传入的参数)
# 保存为 test.sh,执行:bash test.sh apple banana
echo "脚本名:$0"   # 输出:脚本名:test.sh
echo "第一个参数:$1"  # 输出:第一个参数:apple
echo "第二个参数:$2"  # 输出:第二个参数:banana
echo "参数总数:$#"    # 输出:参数总数:2
echo "所有参数:$@"    # 输出:所有参数:apple banana

3. 条件判断(if 语句)

bash 复制代码
# 1. 判断文件是否存在
file="test.txt"
if [ -f "$file" ]; then
    echo "$file 是普通文件"
elif [ -d "$file" ]; then
    echo "$file 是目录"
else
    echo "$file 不存在"
fi

# 2. 数值比较
a=10
b=20
if [ $a -lt $b ]; then  # -lt 表示小于
    echo "$a < $b"      # 输出:10 < 20
fi

# 3. 字符串比较
str1="hello"
str2="hello"
if [ "$str1" = "$str2" ]; then  # = 表示等于(注意空格)
    echo "字符串相等"
else
    echo "字符串不等"
fi

4. 循环结构

for 循环

bash 复制代码
# 1. 遍历列表
fruits=("苹果" "香蕉" "橙子")
for fruit in "${fruits[@]}"; do  # @表示所有元素,加引号处理空格
    echo "我喜欢吃 $fruit"
done
# 输出:
# 我喜欢吃 苹果
# 我喜欢吃 香蕉
# 我喜欢吃 橙子

# 2. 遍历数字范围
for i in {1..3}; do  # 1到3的数字
    echo "计数:$i"
done
# 输出:
# 计数:1
# 计数:2
# 计数:3

while 循环

bash 复制代码
# 从1数到3
count=1
while [ $count -le 3 ]; do  # -le 表示小于等于
    echo "while计数:$count"
    count=$((count + 1))    # 数值自增(等价于 count=$[count+1])
done
# 输出:
# while计数:1
# while计数:2
# while计数:3

5. 函数

bash 复制代码
# 1. 简单函数(无参数)
greet() {
    echo "你好!"
}
greet  # 调用函数,输出:你好!

# 2. 带参数的函数
add() {
    local sum=$(( $1 + $2 ))  # local定义局部变量
    echo $sum                 # 通过echo返回结果
}
result=$(add 5 3)  # 调用函数并获取结果
echo "5 + 3 = $result"  # 输出:5 + 3 = 8

# 3. 带返回值的函数(退出码)
check_file() {
    if [ -f "$1" ]; then
        return 0  # 0表示成功
    else
        return 1  # 非0表示失败
    fi
}
check_file "test.txt"
if [ $? -eq 0 ]; then  # $?获取上一条命令的退出码
    echo "文件存在"
else
    echo "文件不存在"
fi

6. 输入输出重定向与管道

bash 复制代码
# 1. 输出重定向(覆盖写入)
echo "这是一行内容" > output.txt  # 写入到output.txt
cat output.txt  # 查看文件,输出:这是一行内容

# 2. 追加写入
echo "这是第二行内容" >> output.txt
cat output.txt
# 输出:
# 这是一行内容
# 这是第二行内容

# 3. 管道(|):将前一个命令的输出作为后一个命令的输入
ls -l | grep ".sh"  # 筛选当前目录下的.sh文件
cat output.txt | wc -l  # 统计文件行数(输出:2)

7. 数组操作

bash 复制代码
# 定义数组
colors=("红" "绿" "蓝" "黄")

# 访问单个元素(索引从0开始)
echo "第二个元素:${colors[1]}"  # 输出:第二个元素:绿

# 访问所有元素
echo "所有颜色:${colors[@]}"  # 输出:所有颜色:红 绿 蓝 黄

# 数组长度
echo "数组长度:${#colors[@]}"  # 输出:数组长度:4

# 修改元素
colors[2]="青"  # 将第三个元素改为"青"
echo "修改后:${colors[@]}"  # 输出:修改后:红 绿 青 黄

8. 数值计算

bash 复制代码
a=15
b=4

# 加法
echo "$a + $b = $((a + b))"  # 输出:15 + 4 = 19

# 减法
echo "$a - $b = $((a - b))"  # 输出:15 - 4 = 11

# 乘法
echo "$a * $b = $((a * b))"  # 输出:15 * 4 = 60

# 除法(整数除法)
echo "$a / $b = $((a / b))"  # 输出:15 / 4 = 3

# 取余
echo "$a % $b = $((a % b))"  # 输出:15 % 4 = 3

三、综合示例

bash 复制代码
#!/bin/bash
# 文件名: bash_learning.sh
# 描述: 一个用于学习bash脚本编程的示例脚本

# 显示欢迎信息
echo "============================================="
echo "          Bash脚本学习示例程序                "
echo "============================================="

# ----------------------------
# 1. 变量定义与使用
# ----------------------------
echo -e "\n===== 1. 变量定义与使用 ====="
name="Bash学习者"
version=5.1
echo "欢迎你,$name!当前bash版本约为$version"

# 命令替换:将命令结果赋值给变量
current_dir=$(pwd)
echo "当前工作目录: $current_dir"
echo "当前日期: $(date +%Y-%m-%d)"

# ----------------------------
# 2. 环境变量
# ----------------------------
echo -e "\n===== 2. 环境变量 ====="
echo "你的用户名: $USER"
echo "你的家目录: $HOME"
echo "系统路径: $PATH"

# ----------------------------
# 3. 位置参数
# ----------------------------
echo -e "\n===== 3. 位置参数 ====="
echo "脚本名称: $0"
echo "第一个参数: $1"
echo "第二个参数: $2"
echo "参数总数: $#"
echo "所有参数: $*"

# ----------------------------
# 4. 条件判断
# ----------------------------
echo -e "\n===== 4. 条件判断 ====="

# 检查文件是否存在
if [ -f "$0" ]; then
    echo "脚本文件 $0 存在"
else
    echo "脚本文件不存在"
fi

# 数值比较
num1=10
num2=20
if [ $num1 -lt $num2 ]; then
    echo "$num1 小于 $num2"
elif [ $num1 -gt $num2 ]; then
    echo "$num1 大于 $num2"
else
    echo "$num1 等于 $num2"
fi

# 字符串比较
str1="hello"
str2="world"
if [ "$str1" = "$str2" ]; then
    echo "字符串相等"
else
    echo "字符串不相等: $str1 vs $str2"
fi

# ----------------------------
# 5. 循环结构
# ----------------------------
echo -e "\n===== 5. 循环结构 ====="

# for循环遍历列表
echo "for循环遍历列表:"
fruits=("苹果" "香蕉" "橙子" "葡萄")
for fruit in "${fruits[@]}"; do
    echo "水果: $fruit"
done

# for循环数字范围
echo -e "\nfor循环数字范围:"
for i in {1..5}; do
    echo "计数: $i"
done

# while循环
echo -e "\nwhile循环:"
count=1
while [ $count -le 3 ]; do
    echo "while计数: $count"
    count=$((count + 1))  # 数值计算
done

# ----------------------------
# 6. 函数定义与调用
# ----------------------------
echo -e "\n===== 6. 函数 ====="

# 定义函数
greet() {
    local name=$1  # 局部变量
    echo "你好,$name!"
}

# 调用函数
greet "Bash学习者"

# 带返回值的函数
add_numbers() {
    local a=$1
    local b=$2
    echo $((a + b))  # 通过echo返回结果
}

result=$(add_numbers 15 25)
echo "15 + 25 = $result"

# ----------------------------
# 7. 输入输出重定向
# ----------------------------
echo -e "\n===== 7. 输入输出重定向 ====="
echo "这行文字会被写入到临时文件中" > temp_learning.txt
echo "查看临时文件内容:"
cat temp_learning.txt

# ----------------------------
# 8. 管道与过滤
# ----------------------------
echo -e "\n===== 8. 管道与过滤 ====="
echo "当前目录下的.sh文件:"
ls -l | grep "\.sh$"

# ----------------------------
# 9. 数组
# ----------------------------
echo -e "\n===== 9. 数组 ====="
colors=("红色" "绿色" "蓝色")
echo "数组元素: ${colors[@]}"
echo "数组长度: ${#colors[@]}"
echo "第二个元素: ${colors[1]}"

# ----------------------------
# 10. 结束与清理
# ----------------------------
echo -e "\n===== 10. 结束与清理 ====="
rm -f temp_learning.txt  # 删除临时文件
echo "临时文件已清理"
echo -e "\n所有示例执行完毕!希望对你学习bash有所帮助!"

这一世,重生的你不再为批量处理发愁,你学会了如何使用脚本武装自己!

相关推荐
行走在顶尖4 小时前
代码截断运行逻辑
前端
一枚前端小能手4 小时前
「周更第8期」实用JS库推荐:decimal.j
前端·javascript
草莓熊Lotso4 小时前
《C++ Web 自动化测试实战:常用函数全解析与场景化应用指南》
前端·c++·python·dubbo
Tech_Lin4 小时前
JavaScript Date时间对象的常用操作方法总结
前端·javascript
温宇飞4 小时前
JavaScript 异常处理
前端
小岛前端4 小时前
🔥Vue3 移动端组件精选!满足各种场景!
前端·vue.js·微信小程序
用户1510581047434 小时前
带leading和trailing的防抖和节流
前端
IT小哥哥呀4 小时前
论文见解:REACT:在语言模型中协同推理和行动
前端·人工智能·react.js·语言模型
一枚前端小能手4 小时前
🚫 请求取消还在用flag?AbortController让你的异步操作更优雅
前端·javascript