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

shell学习从入门到精通

bShell 语法学习:从入门到精通

Shell 是一个命令解释器,它充当用户与操作系统内核之间的接口。Shell 脚本(Shell Script)则是由一系列 Shell 命令组成的文本文件,用于自动化执行任务。最常用的 Shell 是 Bash (Bourne-Again SHell),本指南将主要以 Bash 为例。

第一部分:入门基础

1. "Hello World" - 你的第一个脚本

学习任何语言的第一步都是 "Hello World"。

  • 脚本内容 (hello.sh):

    #!/bin/bash# 这是一个注释。井号(#)后面的内容会被忽略。
    echo "Hello, World!"
    
  • 关键点解释:

    • #!/bin/bash: 这叫做 "Shebang"。它告诉系统这个脚本应该使用哪个解释器来执行,这里是 /bin/bash

    • #: 这是注释符号。

    • echo: 这是最常用的命令之一,用于在终端输出文本或变量内容。

  • 如何执行脚本:

    • 方法一:作为 bash 的参数

      bash hello.sh
      
    • 方法二:赋予执行权限后直接运行(推荐)

      1. 添加执行权限: chmod +x hello.sh

      2. 执行脚本: ./hello.sh ( ./ 表示当前目录)

2. 变量 (Variables)

变量用于存储数据。Bash 中的变量不需要事先声明类型。

  • 定义和使用:

    • 规则:变量名、等号和值之间 不能有空格

    • 引用:使用 $ 符号。推荐用双引号 "" 包裹变量,以避免空格等特殊字符引起的问题。

    #!/bin/bash# 定义变量
    NAME="Alice"
    AGE=30# 使用变量
    echo "My name is $NAME, and I am $AGE years old."# 推荐使用花括号{}来明确变量边界
    echo "This is ${NAME}'s book." 
    
  • 只读变量:

    CITY="New York"
    readonly CITY
    # 下面这行会报错: CITY: readonly variable
    # CITY="London" 
    
  • 接收用户输入 (read):

    #!/bin/bashecho "What is your name?"
    read USER_NAME
    echo "Hello, $USER_NAME!"# -p 可以在同一行显示提示信息
    read -p "What is your favorite color? " COLOR
    echo "I see, your favorite color is $COLOR."
    
2.1. 变量引用
  • 语法:$变量名 或 ${变量名}(推荐后者,避免歧义)
#!/bin/bashname="Alice"
echo "Name: $name"  # 输出:Name: Alice
echo "Name: ${name}"  # 输出:Name: Alice(推荐)# 变量拼接(无需连接符)
greeting="Hello, ${name}!"
echo $greeting  # 输出:Hello, Alice!# 变量作为命令参数
file="test.txt"
cat ${file}  # 等价于 cat test.txt
2.2. 特殊变量(预定义变量)

Shell 有一系列内置变量,用于获取脚本运行时的信息:

变量含义示例(执行 ./script.sh arg1 arg2
$0脚本文件名echo $0 → ./script.sh
$n第 n 个参数(n≥1)echo $1 → arg1echo $2 → arg2
$#参数总数echo $# → 2
$*所有参数(作为单个字符串)echo $* → arg1 arg2
$@所有参数(作为独立字符串)for i in $@; do echo $i; done → 分别输出 arg1、arg2
$?上一条命令的退出状态(0 成功,非 0 失败)ls non_exist; echo $? → 2(失败)
$$当前脚本的进程 ID(PID)echo $$ → 12345(当前进程 ID)
$!上一个后台进程的 PIDsleep 10 &; echo $! → 后台进程的 PID
#!/bin/bash
# 保存为 args.sh,执行:./args.sh a b cecho "脚本名:$0"  # 输出:脚本名:./args.sh
echo "第1个参数:$1"  # 输出:第1个参数:a
echo "参数总数:$#"  # 输出:参数总数:3
echo "所有参数(\$*):$*"  # 输出:所有参数($*):a b c# 遍历 $@(每个参数独立处理)
echo "遍历 \$@:"
for arg in "$@"; doecho "- $arg"
done
# 输出:
# 遍历 $@:
# - a
# - b
# - c
2.3. 环境变量

环境变量是全局变量,用于配置系统环境(如 PATHHOME),可通过 export 声明。

#!/bin/bash# 查看环境变量(已存在的)
echo "HOME: $HOME"  # 输出:HOME: /home/user(当前用户家目录)
echo "PATH: $PATH"  # 输出:系统命令搜索路径# 定义并导出环境变量(子进程可访问)
export MY_VAR="hello"
# 在当前终端执行脚本后,可通过 echo $MY_VAR 查看(仅当前终端有效)# 临时设置环境变量(仅当前命令有效)
MY_VAR="test" echo $MY_VAR  # 输出:test
3. 命令替换

将一个命令的输出结果赋值给一个变量。

  • 语法: $(command) (推荐) 或 `command` (旧式)

    #!/bin/bashCURRENT_DATE=$(date "+%Y-%m-%d %H:%M:%S")
    FILES_IN_DIR=$(ls -l)echo "Current time is: $CURRENT_DATE"
    echo "---"
    echo "Files in the current directory:"
    echo "$FILES_IN_DIR"
    

4. 数据类型与扩展

Shell 没有严格的数据类型,但支持字符串、数字、数组、关联数组(字典)。

1. 字符串

Shell 字符串可用单引号 '' 或双引号 "",区别:

  • 单引号:不解析变量,不转义特殊字符(除单引号本身)。
  • 双引号:解析变量,可转义特殊字符(如 \n\t)。
#!/bin/bashname="Alice"# 单引号(变量不解析)
echo 'Hello, $name'  # 输出:Hello, $name# 双引号(变量解析)
echo "Hello, $name"  # 输出:Hello, Alice# 转义字符(需双引号)
echo "Line1\nLine2"  # 输出:Line1\nLine2(默认不转义)
echo -e "Line1\nLine2"  # 加 -e 启用转义,输出:
# Line1
# Line2# 字符串长度
str="hello"
echo ${#str}  # 输出:5# 字符串截取(${变量:起始位置:长度},起始位置从0开始)
echo ${str:1:3}  # 从索引1开始,取3个字符 → ell

5. 运算符与表达式

Shell 支持算术运算、字符串运算、逻辑运算,需用特定语法(如 $((...)))。

1. 算术运算符

语法:$((表达式)) 或 $[表达式](推荐前者),支持 +-*/%(取余)、**(幂)。

#!/bin/basha=10
b=3# 加法
echo $((a + b))  # 输出:13# 乘法(注意:* 无需转义,在 $((...)) 中直接用)
echo $((a * b))  # 输出:30# 取余
echo $((a % b))  # 输出:1# 幂运算(Bash 4.0+ 支持)
echo $((2 **3))  # 输出:8# 赋值运算(在表达式中修改变量)
$((a += 5))  # 等价于 a = a + 5
echo $a  # 输出:15
2. 比较运算符(数字)

用于条件判断(if 语句中),语法:[ 数字1 运算符 数字2 ] 或 (( 数字1 运算符 数字2 ))

运算符含义示例(a=10, b=5)
-eq等于[ $a -eq $b ] → false
-ne不等于[ $a -ne $b ] → true
-gt大于[ $a -gt $b ] → true
-lt小于[ $a -lt $b ] → false
-ge大于等于(( a >= b )) → true
-le小于等于(( a <= b )) → false
#!/bin/basha=10
b=5if [ $a -gt $b ]; thenecho "$a 大于 $b"
fi
# 输出:10 大于 5# 用 ((...)) 更简洁(支持 >、< 等符号)
if (( a > b )); thenecho "$a 大于 $b"
fi
# 输出:10 大于 5
3. 字符串运算符

用于字符串比较,语法:[ 字符串1 运算符 字符串2 ] 或 [[ 字符串1 运算符 字符串2 ]]

运算符含义示例(s1="abc", s2="abd")
=等于(== 等价)[ "$s1" = "$s2" ] → false
!=不等于[ "$s1" != "$s2" ] → true
-z字符串长度为 0[ -z "$s1" ] → false
-n字符串长度不为 0[ -n "$s1" ] → true
<字典序小于(需 [[]])[[ "$s1" < "$s2" ]] → true(abc < abd)
>字典序大于(需 [[]])[[ "$s1" > "$s2" ]] → false
#!/bin/bashs1="abc"
s2="abd"# 字符串是否相等
if [ "$s1" = "$s2" ]; thenecho "相等"
elseecho "不相等"
fi
# 输出:不相等# 字符串长度是否不为0
if [ -n "$s1" ]; thenecho "$s1 长度不为0"
fi
# 输出:abc 长度不为0# 字典序比较(需用 [[ ]])
if [[ "$s1" < "$s2" ]]; thenecho "$s1 小于 $s2"
fi
# 输出:abc 小于 abd
4. 逻辑运算符

用于组合条件,支持与(-a 或 &&)、或(-o 或 ||)、非(!)。

#!/bin/basha=10
b=5
c=15# 与运算(两个条件都成立)
if [ $a -gt $b ] && [ $a -lt $c ]; thenecho "$a 大于 $b 且小于 $c"
fi
# 输出:10 大于 5 且小于 15# 或运算(至少一个条件成立)
if [ $a -gt $c ] || [ $a -gt $b ]; thenecho "$a 大于 $c 或大于 $b"
fi
# 输出:10 大于 15 或大于 5# 非运算(条件取反)
if ! [ $a -eq $b ]; thenecho "$a 不等于 $b"
fi
# 输出:10 不等于 5

第二部分:核心语法

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
    
  • 文件系统判断:

    操作符

    描述

    -f

    文件存在且是常规文件

    -d

    文件存在且是目录

    -e

    文件存在(不区分类型)

    -r

    文件可读

    -w

    文件可写

    -x

    文件可执行

    #!/bin/bashFILE="./hello.sh"if [[ -f "$FILE" ]]; thenecho "$FILE is a regular file."if [[ -x "$FILE" ]]; thenecho "And it is executable."fi
    elif [[ -d "$FILE" ]]; thenecho "$FILE is a directory."
    elseecho "$FILE does not exist or is not a regular file/directory."
    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/bashget_full_name() {local first_name=$1local 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[@]}"; doecho "Processing $fruit"
    done
    
  • 关联数组 (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[@]}"; doecho "$key: ${user[$key]}"
    done
    

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
3. 精细数学计算

Shell 内置的 $((...)) 只支持整数运算。对于浮点数或更复杂的计算,需要借助外部工具。

  • 整数计算:

    #!/bin/bashA=10
    B=3SUM=$((A + B))
    PRODUCT=$((A * B))
    REMAINDER=$((A % B)) # 取余echo "Sum: $SUM, Product: $PRODUCT, Remainder: $REMAINDER"
    
  • 浮点数计算 (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"
    
  • 使用 awk 计算: awk 也是一个处理文本和进行计算的强大工具。

    #!/bin/bashRESULT=$(awk "BEGIN {printf \"%.4f\", 10/3}")
    echo "10 / 3 = $RESULT"
    
4. 颜色和格式化输出

通过 ANSI 转义序列设置输出颜色,格式:\033[颜色代码m文本\033[0m0m 重置颜色)

常用颜色代码:

  • 文本色: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}"
      
      • 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 变了
      
    • 输入/输出重定向:

      • >: 重定向标准输出(会覆盖文件内容)。 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
      
    • 进程替换 (<(command)): 这是一个非常高级的特性,它将一个命令的输出伪装成一个文件,然后可以被另一个需要文件作为输入的命令使用。

      # 比较两个目录下的文件列表,而无需创建临时文件
      diff <(ls /bin) <(ls /usr/bin)
      
    • Here 文档(<<

            向命令输入多行文本(无需手动输入),语法

    命令 << 分界符多行文本
    分界符
    

    #!/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(行数)

    第四部分:编写健壮的脚本

    1. set 命令

    在脚本开头使用 set 命令可以使其更安全、更健壮。

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

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

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

    2. 解析脚本选项 (getopts)

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

    #!/bin/bash
    set -euo pipefailVERBOSE=false
    FILENAME=""# f: 表示-f选项需要一个参数
    # v 表示-v选项不需要参数
    while getopts 'vf:' OPTION; docase "$OPTION" inv)VERBOSE=true;;f)FILENAME="$OPTARG";;?)echo "Usage: $(basename $0) [-v] [-f filename]"exit 1;;esac
    doneif [[ $VERBOSE == true ]]; thenecho "Verbose mode is ON."
    fiif [[ -n "$FILENAME" ]]; thenecho "Processing file: $FILENAME"
    elseecho "No filename provided."
    fi
    
    • 执行示例:

      • ./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"
    

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

    #!/bin/bash# 捕获 SIGINT 信号(Ctrl+C)
    trap 'echo " 不要按 Ctrl+C!"; exit 1' SIGINTecho "运行中(按 Ctrl+C 测试)..."
    while true; dosleep 1
    done

    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
    
    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  # ^$ 匹配空行
    
    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

    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,无法捕获)
    
    2. 进程替换(<(命令)>(命令)

    将命令输出作为临时文件,用于需要文件参数的命令。

    #!/bin/bash# 比较两个命令的输出(无需临时文件)
    diff <(ls dir1) <(ls dir2)  # 比较 dir1 和 dir2 的文件列表# 将输出同时发送到终端和文件(tee 命令)
    ls -l | tee >(grep ".sh" > sh_files.txt)  # 筛选 .sh 文件到 sh_files.txt,同时显示所有
    6. 调试脚本
    • bash -n 脚本:检查语法错误(不执行)。
    • bash -x 脚本:执行并输出每一行命令(调试细节)。
    • 在脚本中用 set -x(开启调试)、set +x(关闭)。
    #!/bin/bashset -x  # 开启调试
    a=5
    b=3
    echo $((a + b))
    set +x  # 关闭调试
    echo "调试结束"
    

    第五部分:综合脚本示例

    案例 1:批量重命名文件
    #!/bin/bash
    # 功能:将当前目录所有 .txt 文件重命名为 "prefix_数字.txt"(如 prefix_1.txt)count=1
    for file in *.txt; do# 跳过非文件(如目录)if [ ! -f "$file" ]; thencontinuefi# 重命名mv "$file" "prefix_${count}.txt"echo "重命名:$file → prefix_${count}.txt"((count++))
    done
    
    案例 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 )); thenecho "报警:CPU 使用率过高($cpu_usage%)"
    fi# 检查内存
    if (( mem_usage > MEM_THRESHOLD )); thenecho "报警:内存使用率过高($mem_usage%)"
    fi# 检查磁盘
    if (( disk_usage > DISK_THRESHOLD )); thenecho "报警:磁盘使用率过高($disk_usage%)"
    fi

    总结

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

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

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

    3. 高级: 掌握数组、bc 计算、颜色输出、进程替换、getoptstrap 等高级特性,编写出功能强大、交互友好且非常健壮的专业脚本。

    最重要的是 多写、多练、多看。尝试用脚本去自动化你日常工作中的重复性任务,这是最好的学习方式。

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

    相关文章:

  • 数据仓库:企业数据管理的核心枢纽
  • 创客匠人视角:从信任经济看创始人 IP 如何重塑 IP 变现逻辑
  • nmap扫描指定网段中指定开放端口的主机(IP,mac地址)
  • 量子计算系统软件:让“脆弱”的量子计算机真正可用
  • 有什么好使用的内网ip映射软件?可以让家庭/公司网络局域网端口,让公网互联网跨网访问
  • Spring boot整合dubbo+zookeeper
  • 26-计组-外存
  • 基于云端EC2的O3DE机器人仿真环境搭建指南
  • python自动化面试问题——关于python
  • 029_构造器重载与默认构造器
  • 【报错】Could not find a package configuration file provided by ‘glog’”
  • “Datawhale AI夏令营”基于带货视频评论的用户洞察挑战赛
  • 使用Tensorflow和CNN进行猫狗图片训练的实战总结
  • P1722 矩阵 II 题解 DFS深度优先遍历与卡特兰数(Catalan number)解
  • Spring Boot+Redis+Caffeine 二级缓存架构的终极实现方案、包含万级QPS下的黄金配置参数、全文超过2500字(博君一赞)
  • XGBoosting算法详解(Boosting思想的代表算法)
  • C语言<数据结构-链表>
  • LangChain RAG 实战
  • Transformers 和 PyTorch 的区别与安装指南
  • Docker 高级管理--Dockerfile镜像制作
  • Context Engineering Framework 系统详细介绍
  • 链表算法之【合并两个有序链表】
  • 牛客笔试题 除2!
  • 读取按键的四种方式
  • IMU误差模型
  • 显卡GPU的架构和工作原理
  • 输入框过滤选项列表,el-checkbox-group单选
  • JDK 1.7 vs JDK 1.8
  • 为什么域名加端口访问需要放行端口?
  • 【算法训练营Day11】二叉树part1