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

shell学习从入门到精通(第二部分)

核心语法
1. 条件判断 (if-elif-else)

让脚本根据不同条件执行不同操作。

  • 基本结构:

    if [ condition ]; then# command to execute if condition is true
    elif [ another_condition ]; then# command to execute if another_condition is true
    else# command to execute if all conditions are false
    fi

    关键点:

    if 和 [ 之间必须有空格。

    [ 和 condition 之间以及 condition 和 ] 之间也必须有空格。

    then 必须单独一行,或者用分号 ; 与 if 语句放在同一行:if [ condition ]; then ...

    推荐使用 [[ ... ]],它更强大且不易出错,尤其是在处理字符串时。

    #!/bin/bashread -p "Enter a number: " NUMif [[ $NUM -gt 100 ]]; thenecho "$NUM is greater than 100."
    elif [[ $NUM -eq 100 ]]; thenecho "$NUM is exactly 100."
    elseecho "$NUM is less than 100."
    fi

                                                                                                                                                                                

字符串比较:

操作符

描述

==

等于

!=

不等于

-z

字符串为空

-n

字符串不为空

#!/bin/bashread -p "Enter 'yes' or 'no': " ANSWERif [[ $ANSWER == "yes" ]]; thenecho "You chose 'yes'."
elif [[ $ANSWER != "no" ]]; thenecho "Invalid input."
elseecho "You chose 'no'."
fi
2. case 语句

当有多个分支选择时,case 是比 if-elif-else 更清晰的替代方案。

#!/bin/bashread -p "Enter a character (a, b, or c): " CHARcase $CHAR ina|A)echo "You entered 'a'.";;b|B)echo "You entered 'b'.";;c|C)echo "You entered 'c'.";;*)echo "Invalid character.";;
esac
  • 关键点:

    • | 用于匹配多个模式。

    • *) 是一个通配符,匹配任何其他输入。

    • 每个分支以 ;; 结束。

    • 整个 case 语句以 esac (case反写) 结束。

3. 循环结构
  • for 循环:

  • 遍历列表:

    #!/bin/bashfor FRUIT in apple banana orange; doecho "I like $FRUIT."
    done

    遍历数字序列:

    #!/bin/bashecho "Counting from 1 to 5:"
    for i in {1..5}; doecho $i
    done

    C 语言风格的 for 循环:

    #!/bin/bashfor (( i=0; i<5; i++ )); doecho "C-style loop, iteration: $i"
    done

while 循环: 当条件为真时持续循环。常用于逐行读取文件。

#!/bin/bashCOUNTER=0
while [[ $COUNTER -lt 5 ]]; doecho "Counter is $COUNTER"# 必须有改变条件的语句,否则会死循环let COUNTER++ 
done

逐行读取文件(重要用法):

#!/bin/bashFILENAME="hello.sh"
while IFS= read -r line; doecho "Line: $line"
done < "$FILENAME"
    • IFS= read -r line 是读取文件的标准、安全的方式,可以防止 read 命令意外地处理反斜杠和行首行尾的空白字符。

  • until 循环: 当条件为假时持续循环,直到条件为真。

    #!/bin/bashCOUNTER=0
    until [[ $COUNTER -ge 5 ]]; doecho "Counter is $COUNTER"let COUNTER++
    done

4. 函数 (Functions)

将代码块封装成函数,方便复用。

  • 定义和调用:

    #!/bin/bash# 定义函数
    greet() {echo "Hello there!"
    }# 调用函数
    echo "Calling the function..."
    greet
    echo "Function called."

    传递参数:

  • 在函数内部,$1$2$3, ... 分别代表第一个、第二个、第三个参数。

  • $@ 代表所有参数的列表。

  • $# 代表传递给函数的参数个数。

    #!/bin/bashprint_info() {if [[ $# -eq 0 ]]; thenecho "Usage: print_info <name> <age>"return 1 # 返回一个非零值表示错误fiecho "Name: $1"echo "Age: $2"echo "All arguments: $@"
    }print_info "Bob" 42
    print_info # 测试错误处理

    返回值:

    Shell 函数的 return 语句只返回一个 0-255 的整数,称为 退出状态码。0 通常表示成功,非 0 表示失败。

    要 "返回" 数据,通常是在函数中用 echo 输出,然后在调用处用命令替换 $(...) 来捕获输出。

    local 关键字使变量的作用域仅限于函数内部,这是一个好习惯。

    #!/bin/bash

    get_full_name() {
    local first_name=$1
    local last_name=$2
    # 使用 echo "返回" 结果
    echo "$first_name $last_name"
    }

    # 使用命令替换捕获函数的输出
    FULL_NAME=$(get_full_name "John" "Doe")
    echo "The full name is: $FULL_NAME"

  • 第三部分:高级用法
    1. 数组 (Arrays)
    索引数组 (Indexed Arrays):

    #!/bin/bash

    # 定义数组
    fruits=("Apple" "Banana" "Cherry")

    # 访问元素(索引从0开始)
    echo "First fruit: ${fruits[0]}"

    # 访问所有元素
    echo "All fruits: ${fruits[@]}"

    # 获取数组长度
    echo "Number of fruits: ${#fruits[@]}"

    # 添加元素
    fruits+=("Orange")

    # 遍历数组
    for fruit in "${fruits[@]}"; do
    echo "Processing $fruit"
    done
    AI写代码

    关联数组 (Associative Arrays / Hashes): 键值对数组(需要 Bash 4.0+)。

    #!/bin/bash

    # 声明一个关联数组
    declare -A user

    # 赋值
    user["name"]="Alice"
    user["id"]="101"
    user["email"]="alice@example.com"

    # 访问元素
    echo "User Name: ${user[name]}"

    # 遍历所有的键
    echo "All keys: ${!user[@]}"

    # 遍历所有的值
    echo "All values: ${user[@]}"

    # 遍历键值对
    for key in "${!user[@]}"; do
    echo "$key: ${user[$key]}"
    done
    AI写代码

    2. 字符串处理
    操作    示例    结果
    长度    ${#str}    字符串长度
    截取    ${str:2:3}    从索引 2 开始取 3 个字符
    替换    ${str/old/new}    替换第一个 old 为 new
    全替换    ${str//old/new}    替换所有 old 为 new
    删除前缀    ${str#prefix}    删除最短前缀
    删除后缀    ${str%suffix}    删除最短后缀
    示例:

    #!/bin/bash
    str="hello world"
    echo "长度:${#str}"  # 输出:11
    echo "截取:${str:3:4}"  # 输出:lo w
    echo "替换:${str/world/shell}"  # 输出:hello shell
    AI写代码
    3. 精细数学计算
    Shell 内置的 $((...)) 只支持整数运算。对于浮点数或更复杂的计算,需要借助外部工具。

    整数计算:

    #!/bin/bash

    A=10
    B=3

    SUM=$((A + B))
    PRODUCT=$((A * B))
    REMAINDER=$((A % B)) # 取余

    echo "Sum: $SUM, Product: $PRODUCT, Remainder: $REMAINDER"
    AI写代码

    浮点数计算 (bc): bc 是一个强大的计算器,-l 参数可以加载数学库,支持高精度计算。

    #!/bin/bash

    # 将表达式通过管道传给 bc
    RESULT=$(echo "scale=4; 10 / 3" | bc)
    echo "10 / 3 = $RESULT"

    # 更复杂的计算
    PI=$(echo "scale=10; 4*a(1)" | bc -l) # a() 是反正切函数,4*a(1)是计算pi的经典方法
    echo "Pi ≈ $PI"

    VAR1=5.5
    VAR2=2.2
    SUM=$(echo "$VAR1 + $VAR2" | bc)
    echo "$VAR1 + $VAR2 = $SUM"
    AI写代码

    使用 awk 计算: awk 也是一个处理文本和进行计算的强大工具。

    #!/bin/bash

    RESULT=$(awk "BEGIN {printf \"%.4f\", 10/3}")
    echo "10 / 3 = $RESULT"
    AI写代码
    4. 颜色和格式化输出
    通过 ANSI 转义序列设置输出颜色,格式:\033[颜色代码m文本\033[0m(0m 重置颜色)

    常用颜色代码:

    文本色:30(黑)、31(红)、32(绿)、33(黄)、34(蓝)、35(紫)、36(青)、37(白)
    背景色:40(黑)、41(红)、42(绿)等
    使用 ANSI escape codes 来控制终端输出的颜色和样式。

    语法: \e[...m 或 \033[...m

    示例:

    #!/bin/bash

    # 为了可读性和复用,最好将颜色代码定义为变量
    COLOR_RESET='\e[0m'
    COLOR_RED='\e[31m'
    COLOR_GREEN='\e[32m'
    COLOR_YELLOW='\e[33m'
    BG_BLUE='\e[44m'
    STYLE_BOLD='\e[1m'

    echo -e "${COLOR_RED}This is red text.${COLOR_RESET}"
    echo -e "${COLOR_GREEN}This is green text.${COLOR_RESET}"
    echo -e "${STYLE_BOLD}${COLOR_YELLOW}This is bold yellow text.${COLOR_RESET}"
    echo -e "${BG_BLUE}This text has a blue background.${COLOR_RESET}"

    # 组合使用
    echo -e "${STYLE_BOLD}${COLOR_RED}${BG_BLUE}DANGER! Critical Error!${COLOR_RESET}"
    AI写代码

    echo -e 是必须的,它让 echo 能够解释转义序列。

    5. 强大的命令执行与控制
    命令分组:

    ( ... ): 在一个 子 Shell 中执行命令组。子 Shell 中的变量和目录改变不会影响父 Shell。

    { ...; }: 在 当前 Shell 中执行命令组。注意 } 前必须有分号或换行。

    # 子Shell示例
    echo "Before: PWD=$PWD"
    (cd /tmp; echo "Inside subshell: PWD=$PWD")
    echo "After: PWD=$PWD" # PWD 没变

    # 当前Shell示例
    echo "Before: PWD=$PWD"
    { cd /var; echo "Inside group: PWD=$PWD"; }
    echo "After: PWD=$PWD" # PWD 变了
    AI写代码
    输入/输出重定向:

    >: 重定向标准输出(会覆盖文件内容)。 ls > file.txt

    >>: 重定向标准输出(追加到文件末尾)。date >> file.txt

    <: 重定向标准输入。 read -r line < file.txt

    2>: 重定向标准错误。command_that_fails 2> error.log

    &>: 重定向标准输出和标准错误。command &> all_output.log

    /dev/null: 一个特殊的设备文件,所有写入它的数据都会被丢弃("黑洞")。常用于丢弃不想要的输出。command > /dev/null 2>&1

    管道 (|): 将前一个命令的标准输出作为后一个命令的标准输入。这是 Shell 的精髓之一。

    # 统计当前目录有多少个 .sh 文件
    ls -l | grep ".sh$" | wc -l
    AI写代码
    进程替换 (<(command)): 这是一个非常高级的特性,它将一个命令的输出伪装成一个文件,然后可以被另一个需要文件作为输入的命令使用。

    # 比较两个目录下的文件列表,而无需创建临时文件
    diff <(ls /bin) <(ls /usr/bin)
    AI写代码
    Here 文档(<<)
    向命令输入多行文本(无需手动输入),语法

    命令 << 分界符
    多行文本
    分界符
    AI写代码
    #!/bin/bash

    # 向文件写入多行内容
    cat << EOF > info.txt
    Name: Alice
    Age: 25
    City: Beijing
    EOF
    # info.txt 内容为上述三行

    # 作为函数输入
    count_lines() {
    wc -l
    }

    count_lines << EOF
    line1
    line2
    line3
    EOF
    # 输出:3(行数)
    AI写代码

    第四部分:编写健壮的脚本
    1. set 命令
    在脚本开头使用 set 命令可以使其更安全、更健壮。

    #!/bin/bash
    set -euo pipefail
    AI写代码
    set -e: 脚本中任何命令失败(返回非零退出状态码)时,立即退出。

    set -u: 尝试使用未定义的变量时,立即退出。

    set -o pipefail: 在管道中,只要有任何一个命令失败,整个管道的退出状态码就是失败的。

    2. 解析脚本选项 (getopts)
    用于解析传递给脚本的命令行选项(如 -f, -v)。

    #!/bin/bash
    set -euo pipefail

    VERBOSE=false
    FILENAME=""

    # f: 表示-f选项需要一个参数
    # v 表示-v选项不需要参数
    while getopts 'vf:' OPTION; do
    case "$OPTION" in
    v)
    VERBOSE=true
    ;;
    f)
    FILENAME="$OPTARG"
    ;;
    ?)
    echo "Usage: $(basename $0) [-v] [-f filename]"
    exit 1
    ;;
    esac
    done

    if [[ $VERBOSE == true ]]; then
    echo "Verbose mode is ON."
    fi

    if [[ -n "$FILENAME" ]]; then
    echo "Processing file: $FILENAME"
    else
    echo "No filename provided."
    fi
    AI写代码

    执行示例:

    ./myscript.sh -v -f data.txt

    ./myscript.sh -f report.csv

    3. 信号陷阱 (trap)
    允许你在脚本接收到特定信号(如 Ctrl+C)时执行一段代码,常用于清理临时文件。

    #!/bin/bash
    set -euo pipefail

    # 创建一个临时文件
    TMP_FILE=$(mktemp)
    echo "Created temporary file: $TMP_FILE"

    # 定义清理函数
    cleanup() {
    echo "Caught signal! Cleaning up..."
    rm -f "$TMP_FILE"
    echo "Cleanup finished."
    exit 1
    }

    # 设置陷阱:当接收到 INT(Ctrl+C) 或 TERM 信号时,执行 cleanup 函数
    trap cleanup INT TERM

    # 主逻辑
    echo "Script is running, press Ctrl+C to test the trap."
    sleep 60 # 模拟长时间运行的任务
    echo "Script finished normally."

    # 正常退出前也要清理
    rm -f "$TMP_FILE"
    AI写代码

      捕获系统信号(如 Ctrl+C 发送的 SIGINT),执行自定义操作。

    #!/bin/bash

    # 捕获 SIGINT 信号(Ctrl+C)
    trap 'echo " 不要按 Ctrl+C!"; exit 1' SIGINT

    echo "运行中(按 Ctrl+C 测试)..."
    while true; do
    sleep 1
    done
    AI写代码
    4. 正则表达式与文本处理
    Shell 结合 grep(搜索)、sed(编辑)、awk(分析)可强大处理文本。

    1. grep:文本搜索
    语法:grep [选项] 模式 文件
    常用选项:-i(忽略大小写)、-v(反向匹配)、-n(显示行号)、-E(扩展正则)。
    #!/bin/bash

    # 在文件中搜索包含 "error" 的行(区分大小写)
    grep "error" log.txt

    # 忽略大小写搜索,显示行号
    grep -in "warning" log.txt

    # 反向匹配(不包含 "debug" 的行)
    grep -v "debug" log.txt

    # 扩展正则(-E),匹配 "apple" 或 "banana"
    grep -E "apple|banana" fruits.txt
    AI写代码

    2. sed:文本替换与编辑
    语法:sed [选项] '命令' 文件
    常用命令:s/原字符串/新字符串/(替换,默认替换每行第一个匹配)、s/.../.../g(全局替换)。
    #!/bin/bash

    # 替换文件中 "old" 为 "new"(仅输出,不修改原文件)
    sed 's/old/new/' text.txt

    # 全局替换并修改原文件(-i 选项,备份用 -i.bak)
    sed -i 's/hello/HELLO/g' greet.txt  # 所有 hello 替换为 HELLO

    # 删除空行(d 命令删除匹配行)
    sed '/^$/d' input.txt  # ^$ 匹配空行
    AI写代码

    3. awk:文本分析与处理
    擅长按列处理文本(默认空格分隔),语法:awk '模式 {动作}' 文件。

    #!/bin/bash

    # 打印文件第2列和第4列
    awk '{print $2, $4}' data.txt

    # 按条件过滤(第3列数值 > 100 的行)
    awk '$3 > 100 {print $0}' data.txt  # $0 表示整行

    # 自定义分隔符(-F 选项),按逗号分隔,打印第1列
    awk -F ',' '{print $1}' csvfile.txt
    AI写代码

    5. 进程管理
    Shell 可启动、查看、终止进程。

    1. 后台运行与 jobs
    &:在命令后加 & 使其后台运行。
    jobs:查看当前终端的后台进程。
    fg %n:将第 n 个后台进程调回前台。
    bg %n:将暂停的后台进程继续运行。
    #!/bin/bash

    # 后台运行长时间任务(输出重定向到文件)
    sleep 30 > sleep.log 2>&1 &
    echo "后台进程 ID:$!"  # $! 是后台进程 PID

    # 查看后台进程
    jobs

    # 终止进程(kill)
    pid=$!
    kill $pid  # 发送 SIGTERM 信号
    # kill -9 $pid  # 强制终止(SIGKILL,无法捕获)
    AI写代码

    2. 进程替换(<(命令)、>(命令))
    将命令输出作为临时文件,用于需要文件参数的命令。

    #!/bin/bash

    # 比较两个命令的输出(无需临时文件)
    diff <(ls dir1) <(ls dir2)  # 比较 dir1 和 dir2 的文件列表

    # 将输出同时发送到终端和文件(tee 命令)
    ls -l | tee >(grep ".sh" > sh_files.txt)  # 筛选 .sh 文件到 sh_files.txt,同时显示所有
    AI写代码
    6. 调试脚本
    bash -n 脚本:检查语法错误(不执行)。
    bash -x 脚本:执行并输出每一行命令(调试细节)。
    在脚本中用 set -x(开启调试)、set +x(关闭)。
    #!/bin/bash

    set -x  # 开启调试
    a=5
    b=3
    echo $((a + b))
    set +x  # 关闭调试
    echo "调试结束"
    AI写代码
    第五部分:综合脚本示例
    案例 1:批量重命名文件
    #!/bin/bash
    # 功能:将当前目录所有 .txt 文件重命名为 "prefix_数字.txt"(如 prefix_1.txt)

    count=1
    for file in *.txt; do
    # 跳过非文件(如目录)
    if [ ! -f "$file" ]; then
    continue
    fi
    # 重命名
    mv "$file" "prefix_${count}.txt"
    echo "重命名:$file → prefix_${count}.txt"
    ((count++))
    done
    AI写代码

    案例 2:系统监控脚本
    #!/bin/bash
    # 功能:监控系统 CPU、内存、磁盘使用率,超过阈值则报警

    # 阈值(百分比)
    CPU_THRESHOLD=80
    MEM_THRESHOLD=80
    DISK_THRESHOLD=90

    # 获取 CPU 使用率(取整数)
    cpu_usage=$(top -bn1 | grep "Cpu(s)" | awk '{print $2 + $4}' | cut -d. -f1)

    # 获取内存使用率
    mem_usage=$(free | grep Mem | awk '{print $3/$2 * 100}' | cut -d. -f1)

    # 获取磁盘使用率(根目录)
    disk_usage=$(df -h / | grep / | awk '{print $5}' | sed 's/%//')

    # 检查 CPU
    if (( cpu_usage > CPU_THRESHOLD )); then
    echo "报警:CPU 使用率过高($cpu_usage%)"
    fi

    # 检查内存
    if (( mem_usage > MEM_THRESHOLD )); then
    echo "报警:内存使用率过高($mem_usage%)"
    fi

    # 检查磁盘
    if (( disk_usage > DISK_THRESHOLD )); then
    echo "报警:磁盘使用率过高($disk_usage%)"
    fi
    AI写代码

    总结
    掌握 Shell 脚本是一个循序渐进的过程。

    入门: 从 echo、变量、read 和简单的 if 开始,学会编写和执行基础脚本。

    进阶: 熟练运用循环、函数、case 语句和各种条件判断,能够编写逻辑复杂的脚本。

    高级: 掌握数组、bc 计算、颜色输出、进程替换、getopts 和 trap 等高级特性,编写出功能强大、交互友好且非常健壮的专业脚本。
    ————————————————
    版权声明:本文为CSDN博主「zwjapple」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/zwjapple/article/details/149243023

http://www.lryc.cn/news/602303.html

相关文章:

  • 机器学习sklearn:决策树的参数、属性、接口
  • nccl中__syncthreads的作用及例子 (来自deepseek)
  • 135端口与WMI攻防全解析
  • 网络安全基础知识【4】
  • python中类变量 __slots__ 解析
  • 5190 - 提高:DFS序和欧拉序:树上操作(区域修改1)
  • 排序算法 (Sorting Algorithms)-JS示例
  • AI原生应用:从人机关系重构到数字空间革命
  • RF随机森林分类预测+特征贡献SHAP分析,通过特征贡献分析增强模型透明度,Matlab代码实现,引入SHAP方法打破黑箱限制,提供全局及局部双重解释视角
  • 力扣7:整数反转
  • OCR 赋能合同抽取:不良资产管理公司的效率加速器
  • Kafka 顺序消费实现与优化策略
  • 数据结构之顺序表链表栈
  • 【Git】Linux-ubuntu 22.04 初步认识 -> 安装 -> 基础操作
  • 图片PDF识别工具:扫描PDF文件批量OCR区域图识别改名,识别大量PDF区域内容一次性改名
  • 基于LSTM和GRU的上海空气质量预测研究
  • 图片上传 el+node后端+数据库
  • 如何用VUE实现用户发呆检测?
  • Android通知(Notification)全面解析:从基础到高级应用
  • 【前端】解决Vue3+Pinia中Tab切换与滚动加载数据状态异常问题
  • 05 OpenCV--图像预处理之图像轮廓、直方图均衡化、模板匹配、霍夫变化、图像亮度变化、形态学变化
  • 数据结构:下三角矩阵(Lower Triangular Matrix)
  • MySQL SQL性能优化与慢查询分析实战指南:新手DBA成长之路
  • Eigen 中矩阵的拼接(Concatenation)与 分块(Block Access)操作使用详解和示例演示
  • 简明量子态密度矩阵理论知识点总结
  • 搜索二维矩阵Ⅱ C++
  • 【LeetCode】算法详解#10 ---搜索二维矩阵II
  • 秩为1的矩阵的特征和性质
  • 青少年编程高阶课程介绍
  • 青少年编程中阶课