Linux shell脚本介绍

Shell 是 Linux 和 Unix 系统中的 命令解释器(Command Interpreter),它是用户与操作系统之间的桥梁,允许用户输入命令来控制计算机的行为。Shell 既可以用于 交互式操作(输入命令后立即执行),也可以用于编写 Shell 脚本,实现自动化任务。

不同的 Linux 发行版可能使用不同的 Shell,最常见的有:

  • Bash(Bourne Again Shell):最流行的 Shell,默认用于大多数 Linux 发行版。
  • Zsh(Z Shell):功能更强大的 Shell,支持更好的自动补全和插件系统。
  • Sh(Bourne Shell):早期的 Shell,Bash 的前身。
  • Csh(C Shell):语法类似 C 语言,较少使用。
  • Ksh(Korn Shell):比 Sh 更强大,但没 Bash 流行。

通过以下命令查看当前使用的 Shell

root@huhy:~# echo $SHELL
/bin/bash

Shell 适合哪些场景?

✅ 运维管理(如定时备份、日志分析)
✅ 自动化任务(如批量重命名文件、下载数据)
✅ 服务器管理(如部署应用、批量执行命令)
✅ 软件开发(如 CI/CD 流水线、构建工具)

入门案例

系统环境:Ubuntu2404

(1)创建脚本

vim test.sh
#!/bin/bash
a='hello word'
echo $a
echo '$a'
echo "$a"

代码含义

  • #!/bin/bash
    作用:Shebang(哈希符 + 感叹号)声明,指定脚本的解释器路径。

  • echo ‘hello world’
    作用:输出字符串hello world到终端。

  • 引号的区别
    不加引号时,Shell 会解析变量,并且空格和特殊字符可能导致问题。(例如*、/、\、$等字符
    单引号内的内容完全原样输出,不解析变量或特殊字符。(严格的文本模式,单引号内的所有内容都不会被解析,包括变量 $USER
    双引号内的内容解析变量和命令,但保留大部分字符的原义。(变量会被解析,例如 $USER 会被替换为当前用户。
    允许使用转义字符,但不会解析 Shell 特殊字符

方式 变量解析 命令解析 转义字符解析 空格是否保留
不加引号 ✅ 解析 ✅ 解析 ❌ 不解析 ❌ 不保留
单引号 ’ ❌ 不解析 ❌ 不解析 ❌ 不解析 ✅ 保留
双引号 " ✅ 解析 ✅ 解析($()) ✅ 解析 ✅ 保留
  • 什么时候用哪种引号
    ✅ 不加引号 → 仅适用于简单变量(没有空格或特殊字符)。
    ✅ 单引号 ’ → 确保内容原封不动(不解析变量和命令)。
    ✅ 双引号 " → 允许变量和命令解析,但保留整体格式(大多数情况建议用)。

(2)执行脚本

在 Linux 中,执行 Shell 脚本的方式有三种:

  • 直接用 bash 或 sh 执行
    ✅ 不会修改当前 Shell 环境,脚本在 子 Shell 中运行,不影响当前终端的变量。
    ✅ 不需要可执行权限(chmod +x 不是必须的)。
    ✅ bash 和 sh 可能有区别:

    • bash test.sh 运行在 Bash 环境下,支持 Bash 特性。
    • sh test.sh 运行在 sh(可能是 Dash)环境下,不支持 Bash 特有功能(如 [[ … ]] 语法)。
  • 直接执行脚本 ./test.sh
    ✅ 需要可执行权限(chmod +x test.sh 之后才能运行)。
    ✅ 使用脚本的 shebang 指定的 Shell(如 #!/bin/bash)。
    ✅ 不会修改当前 Shell 环境,仍然在 子 Shell 运行。

  • 使用 source 或 . 执行
    ✅ 在当前 Shell 中运行,不会启动新的子 Shell。
    ✅ 可以修改当前 Shell 变量
    ✅ 不需要可执行权限,直接运行即可

方式 是否需要执行权限 是否影响当前Shell 适用场景
bash test.sh ❌ 不需要 ❌ 运行在子 Shell 通用,适用于 Bash
sh test.sh ❌ 不需要 ❌ 运行在子 Shell 兼容所有 Shell
./test.sh ✅ 需要 (chmod +x) ❌ 运行在子 Shell 推荐,遵循 #!/bin/bash
source test.sh ❌ 不需要 ✅ 影响当前 Shell 适用于环境变量、配置文件

bash和sh执行:除了单引号外,其他的变量都被正确输出

root@huhy:~# bash test.sh
hello word
$a
hello word
root@huhy:~# sh test.sh
hello word
$a
hello word
root@huhy:~#

使用 ./test.sh则需要添加可执行权限

root@huhy:~# ./test.sh
bash: ./test.sh: Permission denied
root@huhy:~# chmod +x test.sh
root@huhy:~# ./test.sh
hello word
$a
hello word

使用source执行前,变量a不会影响当前shell环境,使用source后则会影响

root@huhy:~# echo $a

root@huhy:~# source test.sh
hello word
$a
hello word
root@huhy:~# echo $a
hello word
root@huhy:~#

变量与环境

Shell 变量用于存储数据,分为本地变量和环境变量。

  • 定义变量
    等号 = 两边不能有空格,否则会报错。
    变量值可以是字符串或数字,但 Shell 默认是字符串处理。
    变量名称推荐使用大写,但不是必须的。

示例

#!/bin/bash
NAME='huhy'
  • 交互式定义变量
    通过read获取用户输入的字符作为变量值

示例

root@huhy:~# cat test.sh
#!/bin/bash
echo "Enter your name:"
read USERNAME
echo "Hello, $USERNAME"
root@huhy:~# bash test.sh
Enter your name:
huhy    #输入后需要回车
Hello, huhy
  • 访问变量
    使用 $变量名 访问变量
    变量用 “” 包裹时,支持变量解析
    如果变量名紧挨其他字符,可用 大括号 {} 确保正确解析

示例

root@huhy:~# cat test.sh
#!/bin/bash
NAME='huhy'
echo "hello,$NAME,${NAME}aaa"
root@huhy:~# bash test.sh
hello,huhy,huhyaaa
  • 变量作用域
    本地变量:变量仅在当前 Shell 进程内有效
    环境变量:环境变量可以被子进程继承,使用export设置
#!/bin/bash
USERNAME='huhy'
echo "Hello, $USERNAME"
root@huhy:~# bash test.sh
Hello, huhy
root@huhy:~# echo $USERNAME

root@huhy:~# export USERNAME='huhy'
root@huhy:~# vi test.sh
root@huhy:~# cat test.sh
#!/bin/bash
echo "Hello, $USERNAME"
root@huhy:~# bash test.sh
Hello, huhy
root@huhy:~# echo $USERNAME
huhy
  • 变量删除
    使用unset清除变量
root@huhy:~# echo $USERNAME
huhy
root@huhy:~# unset USERNAME
root@huhy:~# echo $USERNAME

  • 查看所有环境变量
printenv   # 列出所有环境变量
env        # 同上
echo $HOME  # 查看某个变量
  • 修改环境变量
    临时修改(仅当前会话有效):
export PATH="/usr/local/bin:$PATH"

永久修改(添加到 ~/.bashrc 或 ~/.bash_profile):

echo 'export PATH="/usr/local/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
  • 特殊变量
    Shell 提供了一些特殊变量:
变量 作用
$0 脚本名称
$1 至 $9 位置参数
$# 位置参数个数
$@ 所有参数(每个参数独立)
“$*” 所有参数(作为单个字符串)
$? 上一个命令的返回值
$$ 当前进程 ID
$! 最后一个后台进程 ID

示例

root@huhy:~# cat test.sh
#!/bin/bash
USERNAME='huhy'
echo "Hello, $USERNAME"
echo "脚本名: $0"
echo "第一个参数: $1"
echo "参数个数: $#"
echo "所有参数: $@"
echo "当前进程 ID: $$"
root@huhy:~# bash test.sh ok
Hello, huhy
脚本名: test.sh
第一个参数: ok
参数个数: 1
所有参数: ok
当前进程 ID: 4768
  • 变量相关的高级用法

示例

root@huhy:~# cat test.sh
#!/bin/bash

# 若 VAR 未定义,则输出 “默认值”
echo ${VAR:-"默认值"}


STR="Hello"
echo ${
    
    #STR}  # 获取变量长度为5

# 截取字符串长度
CHAR="HelloWorld"
echo ${CHAR:0:5}  # Hello
echo ${CHAR:5}    # World

root@huhy:~# bash test.sh
默认值
5
Hello
World

运算符与字符串处理

  • 算术运算符
    Shell 不能直接进行算术运算,而是借助 (( ))、$(( ))、expr 或 bc 进行计算
运算符 作用 示例
加法 echo $((3 + 2))
减法 echo $((5 - 2))
x 乘法 echo $((4 * 3))
/ 除法 echo $((8 / 2))
% 取余 echo $((5 % 2))
** 幂运算 echo $((2 ** 3))

示例 :$(( )) 计算

root@huhy:~# cat test.sh
#!/bin/bash
a=10
b=5
sum=$((a + b))
echo "Sum: $sum"  # 输出: Sum: 15
root@huhy:~# bash test.sh
Sum: 15

示例 :expr 计算

root@huhy:~# cat test.sh
#!/bin/bash
a=10
b=5
sum=$(expr $a + $b)
echo "Sum: $sum"  # 输出: Sum: 15
root@huhy:~# bash test.sh
Sum: 15

示例 :bc 计算浮点数

root@huhy:~# cat test.sh
#!/bin/bash
a=10.5
b=3.2
sum=$(echo "$a + $b" | bc)
echo "Sum: $sum"  # 输出: Sum: 13.7
root@huhy:~# bash test.sh
Sum: 13.7
  • 关系运算符(整数比较)
    Shell 仅支持整数比较,使用 -eq、-ne 等
运算符 作用 示例
-eq 等于 [ “$ a” -eq “$ b” ]
-ne 不等于 [ “$ a” -ne “$ b” ]
-gt 大于 [ “$ a” -gt “$ b” ]
-lt 小于 [ “$ a” -lt “$ b” ]
-ge 大于等于 [ “$ a” -ge “$ b” ]
-le 小于等于 [ “$ a” -le “$ b” ]

示例

root@huhy:~# cat test.sh
#!/bin/bash
a=10
b=5

if [ "$a" -gt "$b" ]; then
    echo "$a 大于 $b"
fi
root@huhy:~# bash test.sh
10 大于 5
  • 逻辑运算符
    逻辑运算符用于条件判断。
运算符 作用 示例
&& 逻辑 AND [ “$ a” -gt 5 ] && [ “$ b” -lt 10 ]
ll 逻辑 OR [ “$ a” -gt 5 ] ll [ “$ b” -lt 10 ]
! 逻辑 NOT ![ “$ a” -lt 5 ]

示例

root@huhy:~# cat test.sh
#!/bin/bash
a=10
b=5
# 判断 a>5 和 b<10
if [ "$a" -gt 5 ] && [ "$b" -lt 10 ]; then
    echo "条件满足"
fi
root@huhy:~# bash test.sh
条件满足
  • 文件测试运算符
    Shell 提供文件相关的测试运算符
运算符 作用 示例
-f 是否是文件 [ -f “file.txt” ]
-d 是否是目录 [ -d “/home/user” ]
-e 文件是否存在 [ -e “file.txt” ]
-r 是否可读 [ -r “file.txt” ]
-w 是否可写 [ -w “file.txt” ]
-x 是否可执行 [ -x “script.sh” ]

示例

root@huhy:~# cat test.sh
#!/bin/bash
if [ -f "/etc/passwd" ]; then
    echo "文件存在"
else
    echo "文件不存在"
fi
root@huhy:~# bash test.sh
文件存在
  • 字符串比较
    Shell 也支持字符串比较。
运算符 作用 示例
= 等于 [ “ a " = " a" = " a"="b” ]
!= 不等于 [ “ a " ! = " a" != " a"!="b” ]
-z 是否为空 [ -z “$a” ]
-n 是否非空 [ -n “$a” ]

示例

root@huhy:~# cat test.sh
#!/bin/bash
str1="hello"
str2="world"

if [ "$str1" = "$str2" ]; then
    echo "两个字符串相等"
else
    echo "两个字符串不相等"
fi
root@huhy:~# bash test.sh
两个字符串不相等

条件判断与控制语句

在 Shell 编程中,条件判断和控制语句(如 if、case、for、while)是编写逻辑的核心,能让脚本执行不同的操作

(1)条件判断

  • if 语句
    适用于单个或多个条件的判断。
    可以和 test([ ])、[[ ]] 或 (( )) 结合使用。
    适用于数值、字符串、文件的判断。

Shell 的 if 语句格式如下:

if [ 条件 ]; then
    # 代码块
elif [ 条件 ]; then
    # 代码块
else
    # 代码块
fi

示例 :判断变量是否为空

root@huhy:~# cat test.sh
#!/bin/bash
name=""

if [ -z "$name" ]; then
    echo "name 变量为空"
else
    echo "name 变量值为: $name"
fi
root@huhy:~# bash test.sh
name 变量为空
  • 示例 2:判断两个数的大小
root@huhy:~# cat test.sh
#!/bin/bash
a=10
b=20

if [ "$a" -gt "$b" ]; then
    echo "$a 大于 $b"
elif [ "$a" -lt "$b" ]; then
    echo "$a 小于 $b"
else
    echo "$a 等于 $b"
fi
root@huhy:~# bash test.sh
10 小于 20

应用场景:数值比较、字符串比较、文件属性判断 、多条件组合

(2)控制语句

  • case 语句
    适用于多个离散值的匹配(类似 switch-case)。
    比 if 更简洁,不适用于范围判断。

语法格式如下

case $变量 in
    值1) 命令 ;;
    值2) 命令 ;;
    *)   默认命令 ;;
esac

示例

root@huhy:~# cat test.sh
#!/bin/bash
echo "输入一个数字:"
read num

case $num in
    1) echo "你选择了 1" ;;
    2) echo "你选择了 2" ;;
    3) echo "你选择了 3" ;;
    *) echo "无效输入" ;;
esac
root@huhy:~# bash test.sh
输入一个数字:
1
你选择了 1
root@huhy:~# bash test.sh
输入一个数字:
5
无效输入

应用场景:菜单选项、用户输入处理、多个固定值的判断

  • for 循环
    适用于已知次数的循环。
    可用于遍历列表、数组、文件

基本格式如下:

for 变量 in 值1 值2 值3; do
    命令
done

示例

root@huhy:~# cat test.sh
#!/bin/bash
for name in A B C; do
    echo "Hello, $name"
done
root@huhy:~# bash test.sh
Hello, A
Hello, B
Hello, C

示例:换为C 风格循环

root@huhy:~# cat test.sh
#!/bin/bash
for ((i=1; i<=5; i++)); do
    echo "循环第 $i 次"
done
root@huhy:~# bash test.sh
循环第 1 次
循环第 2 次
循环第 3 次
循环第 4 次
循环第 5

应用场景:遍历列表(如文件、字符串、数组)、执行固定次数的任务

  • while 循环
    适用于未知次数的循环,直到条件不满足才退出。
    常用于处理用户输入、网络请求等动态条件的场景。

基本格式如下

while [ 条件 ]; do
    命令
done

示例

root@huhy:~# cat test.sh
#!/bin/bash
count=1

while [ "$count" -le 5 ]; do
    echo "第 $count 次循环"
    ((count++))
done
root@huhy:~# bash test.sh1 次循环
第 2 次循环
第 3 次循环
第 4 次循环
第 5 次循环

用户输入示例

root@huhy:~# cat test.sh
#!/bin/bash
while true; do
    echo "请输入 'exit' 退出:"
    read input
    if [ "$input" = "exit" ]; then
        break
    fi
    echo "你输入的是: $input"
done

root@huhy:~# bash test.sh
请输入 'exit' 退出:
3
你输入的是: 3
请输入 'exit' 退出:
2
你输入的是: 2
请输入 'exit' 退出:
exit

应用场景:等待某个条件满足、处理动态输入

  • until 循环
    与 while 相反,直到条件为真才结束。
    适用于必须执行至少一次的循环。
until [ 条件 ]; do
    命令
done

示例

root@huhy:~# cat test.sh
#!/bin/bash
count=1

until [ "$count" -gt 5 ]; do
    echo "第 $count 次循环"
    ((count++))
done
root@huhy:~# bash test.sh1 次循环
第 2 次循环
第 3 次循环
第 4 次循环
第 5 次循环

应用场景:等待某个事件发生、反向控制逻辑

  • 跳出循环
    break 立即终止整个循环
    continue 跳过当前循环,执行下一次

示例:break

#!/bin/bash
for i in {
    
    1..10}; do
    if [ "$i" -eq 5 ]; then
        break
    fi
    echo "当前数值: $i"
done
root@huhy:~# bash test.sh
当前数值: 1
当前数值: 2
当前数值: 3
当前数值: 4

示例:continue

root@huhy:~# cat test.sh
#!/bin/bash
for i in {
    
    1..5}; do
    if [ "$i" -eq 3 ]; then
        continue
    fi
    echo "当前数值: $i"
done
root@huhy:~# bash test.sh
当前数值: 1
当前数值: 2
当前数值: 4
当前数值: 5

相当于多执行了一次循环

  • 总结与对比
语句 适用场景 适用范围 主要特点
if 需要执行不同的代码块 数值、字符串、文件判断 适用于逻辑分支
case 处理多个固定值 字符串、用户输入 适用于菜单选项
for 已知次数循环 数组、列表、C 风格循环 适用于固定次数的任务
while 未知次数循环 变量、用户输入 适用于等待特定条件
until 直到条件成立才终止 变量、用户输入 适用于反向控制逻辑
break 终止循环 for、while、until 用于提前退出循环
continue 跳过当前循环 for、while、until 用于跳过当前迭代

数组与函数

在 Shell 脚本编程中,数组 和 函数 是提高代码组织性和复用性的重要工具。以下将详细介绍 数组(包括一维数组和关联数组)与 函数(包括参数、返回值、递归等)。

(1)数组

  • 数组声明
# 声明数组
arr=("Apple" "Banana" "Cherry")
  • 访问数组元素
echo "${arr[0]}"  # Apple
echo "${arr[1]}"  # Banana
  • 获取数组所有元素
echo "${arr[@]}"  # Apple Banana Cherry
echo "${arr[*]}"  # Apple Banana Cherry
  • 获取数组长度
echo "${
     
     #arr[@]}"  # 3
  • 遍历数组
for item in "${arr[@]}"; do
    echo "$item"
done
  • 添加元素
arr+=("Date")
echo "${arr[@]}"  # Apple Banana Cherry Date
  • 修改元素
arr[1]="Blueberry"
echo "${arr[@]}"  # Apple Blueberry Cherry Date
  • 删除元素
unset arr[1]
echo "${arr[@]}"  # Apple Cherry Date

(2)函数

  • 定义函数

语法格式如下:

function 函数名() {
    
    
    命令
}
# 或
函数名() {
    
    
    命令
}

示例

root@huhy:~# cat test.sh
#!/bin/bash
hello() {
    
    
    echo "Hello, Shell!"
}

hello  # 调用函数
root@huhy:~# bash test.sh
Hello, Shell!
  • 带参数的函数

访问参数

符号 含义
$0 脚本文件名
$1~$9 位置参数
$# 参数个数
$@ 所有参数(保持原样)
$* 所有参数(合并成单字符串)

示例

oot@huhy:~# cat test.sh
#!/bin/bash
greet() {
    
    
    echo "Hello, $1! Your age is $2."
}

greet "Alice" 25  # Hello, Alice! Your age is 25.
root@huhy:~# bash test.sh
Hello, Alice! Your age is 25.
  • 返回值
    Shell 函数返回值只能是整数(0-255),可以用 echo 返回字符串

使用 return 返回整数

root@huhy:~# cat test.sh
#!/bin/bash
check_number() {
    
    
    if [ "$1" -gt 10 ]; then
        return 0  # 表示成功
    else
        return 1  # 表示失败
    fi
}

check_number 15
echo $?  # 0 (成功)
root@huhy:~# bash test.sh
0

使用 echo 返回字符串

root@huhy:~# cat test.sh
#!/bin/bash
get_name() {
    
    
    echo "Alice"
}

name=$(get_name)
echo "My name is $name"  # My name is Alice
root@huhy:~# bash test.sh
My name is Alice
  • 变量作用域
    默认情况下,Shell 变量是全局变量,可以用 local 声明局部变量
root@huhy:~# cat test.sh
#!/bin/bash
scope_test() {
    
    
    local var="Local"
    echo "Inside function: $var"
}

var="Global"
scope_test
echo "Outside function: $var"
root@huhy:~# bash test.sh
Inside function: Local
Outside function: Global

进程管理与调试

在 Shell 脚本编程和 Linux 系统管理中,进程管理 和 调试技巧 是至关重要的。进程管理涉及后台运行、进程控制、信号处理等,而调试技术有助于发现并修复 Shell 脚本中的错误

(1)进程管理
进程管理用于控制脚本或程序的运行状态,包括前台、后台、挂起、终止等操作

  • 查看当前进程
    a:显示所有用户的进程
    u:显示进程的用户信息
    x:显示无终端控制的进程
    -e:显示所有进程
    -f:显示完整格式
root@huhy:~# ps -aux
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root           1  0.0  0.3  22016 12840 ?        Ss   02:45   0:01 /sbin/init
root           2  0.0  0.0      0     0 ?        S    02:45   0:00 [kthreadd]
root           3  0.0  0.0      0     0 ?        S    02:45   0:00 [pool_workqueue_release]
---------
  • 进程后台运行
    后台运行进程:在命令后添加 nohup和 & 可让进程在后台运行
    2>&1:不显示打印信息
root@huhy:~# cat test.sh
#!/bin/bash
while true; do
        echo 'ok'
done
root@huhy:~# nohup bash test.sh 2>&1 &
[1] 1742
root@huhy:~# nohup: ignoring input and appending output to 'nohup.out'

root@huhy:~# jobs
[1]+  Running                 nohup bash test.sh 2>&1 &
  • 终止进程
    查找进程号并结束
root@huhy:~# ps -aux | grep test
root        1742 99.9  0.0   7340  3456 pts/0    R    03:24   1:13 bash test.sh
root        1748  0.0  0.0   6544  2304 pts/0    S+   03:25   0:00 grep --color=auto test
root@huhy:~# kill -9 1742
root@huhy:~# jobs
[1]+  Killed                  nohup bash test.sh 2>&1
  • 调试 Shell 脚本
    调试是发现和修复错误的关键。Shell 提供了多种调试方式,如 set 选项、trap、echo 输出等。

使用 set 进行调试

选项 作用
set -x 显示执行的每一条命令
set -e 发生错误时立即退出
set -u 遇到未定义变量时报错
set -o pipefail 任意管道命令失败时,整个管道失败

示例:显示命令执行,并且发生错误时立即退出

root@huhy:~# cat test.sh
#!/bin/bash
#!/bin/bash
set -x # 开启调试模式
set -e # 发生错误时立即退出
echo"Hello, World"
ls /nonexistent_dir # 这里会出错
ls /opt
echo "ok"
set +x # 关闭调试模式
root@huhy:~# bash test.sh
+ set -e
+ echo '“Hello, World'
“Hello, World
+ ls /nonexistent_dir
ls: cannot access '/nonexistent_dir': No such file or directory
  • trap 进行错误捕获
root@huhy:~# cat test.sh
#!/bin/bash

trap 'echo "错误发生在第 $LINENO 行,命令: $BASH_COMMAND"' ERR

set -x # 开启调试模式
set -e #发生错误时立即退出
echo"Hello, World"
ls /nonexistent_dir # 这里会出错
ls /opt
echo "ok"
set +x # 关闭调试模式
root@huhy:~# bash test.sh
+ set -e
+ echo '“Hello, World'
“Hello, World
+ ls /nonexistent_dir
ls: cannot access '/nonexistent_dir': No such file or directory
++ echo '错误发生在第 8 行,命令: ls /nonexistent_dir'
错误发生在第 6行,命令: ls /nonexistent_dir
  • 日志记录
    使用 exec 记录日志:然后在 logfile.log 里查看执行日志
root@huhy:~# cat test.sh
#!/bin/bash

exec > logfile.log 2>&1  # 标准输出和错误输出都重定向到文件

trap 'echo "错误发生在第 $LINENO 行,命令: $BASH_COMMAND"' ERR
set -x # 开启调试模式
set -e #发生错误时立即退出
echo"Hello, World"
ls /nonexistent_dir # 这里会出错
ls /opt
echo "ok"
set +x # 关闭调试模式
root@huhy:~# bash test.sh
root@huhy:~# tail -f logfile.log
+ set -e
+ echo '“Hello, World'
“Hello, World
+ ls /nonexistent_dir
ls: cannot access '/nonexistent_dir': No such file or directory
++ echo '错误发生在第 7 行,命令: ls /nonexistent_dir'
错误发生在第 7 行,命令: ls /nonexistent_dir

文本处理

常用文本提取

  • 获取网卡IP地址
    ip a -4 show ens33显示具体网卡信息,不包含IPv6
    awk ‘/inet / {print $2}’ 过滤 inet 行并提取第二列(IP 地址)。
    awk -F’/’ ‘{print $1}’ 以 / 分隔,取第一个字段(去掉子网掩码)。
root@huhy:~# ip -4 a | awk '/inet / && !/127.0.0.1/ {print $2}' | awk -F'/' '{print $1}'
192.168.200.160
192.168.200.170
root@huhy:~# ip -4 a show ens33 | awk '/inet / && !/127.0.0.1/ {print $2}' | awk -F'/' '{print $1}'
192.168.200.160
root@huhy:~#

或者

root@huhy:~# hostname -I | awk '{print $1}'
192.168.200.160
  • 获取 MAC 地址
root@huhy:~# ip link show | awk '/ether/ {print $2}'
00:0c:29:64:d5:35
00:0c:29:64:d5:3f
  • 获取默认网关
root@huhy:~# ip route | awk '/default/ {print $3}'
192.168.200.2
  • 获取 CPU 型号
root@huhy:~# awk -F: '/model name/ {print $2; exit}' /proc/cpuinfo
 13th Gen Intel(R) Core(TM) i7-13700
  • 获取 CPU 核心数
root@huhy:~# awk '/^processor/ {count++} END {print count}' /proc/cpuinfo
4
  • 获取总内存大小
root@huhy:~# awk '/MemTotal/ {print $2/1024 " MB"}' /proc/meminfo
3868.17 MB
  • 获取可用内存
root@huhy:~# awk '/MemAvailable/ {print $2/1024 " MB"}' /proc/meminfo
3355.34 MB
  • 获取磁盘使用率
root@huhy:~# df -h | awk '$NF=="/" {print $5}'
14%
  • 获取所有磁盘分区使用情况
root@huhy:~# df -h | awk 'NR>1 {print $1, $5}'
tmpfs 1%
/dev/mapper/ubuntu--vg-ubuntu--lv 14%
tmpfs 0%
tmpfs 0%
/dev/sda2 6%
tmpfs 1%

练习案例

帮助强化理解

批量创建用户

批量创建Linux用户

vi user_create.sh
#!/bin/bash

# 配置项
USER_LIST="users.txt"         # 存放用户名的文件,每行一个
PASSWORD_LENGTH=12            # 随机密码长度
DEFAULT_PASSWORD=""           # 统一默认密码(留空则使用随机密码)
LOG_FILE="user_creation.log"  # 记录日志
DEFAULT_SHELL="/bin/bash"     # 默认 Shell
EXPIRE_DAYS=90                # 账户过期时间(可选)

# 生成随机密码
generate_password() {
    
    
    tr -dc 'A-Za-z0-9@#$%&' </dev/urandom | head -c "$PASSWORD_LENGTH"
}

# 检查 root 权限
if [[ $EUID -ne 0 ]]; then
    echo "错误: 请使用 root 权限运行此脚本!"
    exit 1
fi

# 检查用户列表文件是否存在
if [[ ! -f "$USER_LIST" ]]; then
    echo "错误: 用户列表文件 $USER_LIST 不存在!"
    exit 1
fi

echo "开始创建用户..."

# 读取用户列表并创建用户
while IFS= read -r username; do
    # 跳过空行
    [[ -z "$username" ]] && continue

    # 检查用户名是否合法 (只能包含字母、数字、下划线,长度1-32)
    if [[ ! "$username" =~ ^[a-zA-Z0-9_]{
    
    1,32}$ ]]; then
        echo "警告: 无效的用户名 '$username',跳过..." | tee -a "$LOG_FILE"
        continue
    fi

    # 检查用户是否已存在
    if id "$username" &>/dev/null; then
        echo "警告: 用户 '$username' 已存在,跳过..." | tee -a "$LOG_FILE"
        continue
    fi

    # 确定密码(优先使用默认密码,否则生成随机密码)
    if [[ -n "$DEFAULT_PASSWORD" ]]; then
        password="$DEFAULT_PASSWORD"
    else
        password=$(generate_password)
    fi

    # 创建用户(带 home 目录、默认 shell)
    useradd -m -s "$DEFAULT_SHELL" -e "$(date -d "+$EXPIRE_DAYS days" +%F)" "$username"

    # 设置密码
    echo "$username:$password" | chpasswd

    # 记录日志
    echo "用户 '$username' 创建成功,密码: $password" | tee -a "$LOG_FILE"

done < "$USER_LIST"

echo "批量创建用户完成,详细日志请查看 $LOG_FILE"
root@huhy:~# cat users.txt
user01
user02
user03
root@huhy:~# bash user_create.sh
开始创建用户...
用户 'user01' 创建成功,密码: dG9wFR6m9nTQ
用户 'user02' 创建成功,密码: 1@hqyuweBN7G
用户 'user03' 创建成功,密码: kbHzQ1Wq25vU
批量创建用户完成,详细日志请查看 user_creation.log
root@huhy:~# tail -f user_creation.log
用户 'user01' 创建成功,密码: dG9wFR6m9nTQ
用户 'user02' 创建成功,密码: 1@hqyuweBN7G
用户 'user03' 创建成功,密码: kbHzQ1Wq25vU
  • 功能特点
    ✅ 两种密码创建方式(随机生成或指定默认密码)
    ✅ 默认密码未设置时自动使用随机密码
    ✅ 防止重复创建
    ✅ 记录详细日志
    ✅ 账户过期时间支持
监控系统资源

简易实现监控Linux的网络、磁盘、内存等资源信息

vi monitor.sh
#!/bin/bash

# 清空屏幕并进入全屏模式
tput clear
tput civis   # 隐藏光标,增加美观性
tput cup 0 0 # 定位到屏幕最上方(行 0 列 0)

while true; do
    CURRENT_TIME=$(date '+%Y-%m-%d %H:%M:%S')

    # 打印系统信息
    echo -e "\033[1;32m=========== 系统信息 ===========\033[0m"
    echo -e "主机名     : $(hostname)"
    echo -e "操作系统   : $(grep 'PRETTY_NAME' /etc/os-release | cut -d '=' -f2 | tr -d '\"')"
    echo -e "内核版本   : $(uname -r)"
    echo -e "CPU 型号   : $(awk -F: '/model name/ {print $2; exit}' /proc/cpuinfo | sed 's/^ *//')"
    echo -e "运行时间   : $(uptime -p)"
    echo -e "当前时间   : $CURRENT_TIME"

    # 切换到下一行位置
    tput cup 7 0

    # 打印 CPU 信息
    echo -e "\033[1;32m=========== CPU 信息 ===========\033[0m"
    CPU_USAGE=$(top -bn1 | grep "Cpu(s)" | awk '{print 100 - $8"%"}')
    echo -e "CPU 使用率 : $CPU_USAGE"

    # 切换到下一行位置
    tput cup 10 0

    # 打印内存信息
    echo -e "\033[1;32m=========== 内存信息 ===========\033[0m"
    TOTAL_MEM=$(free -m | awk '/Mem:/ {print $2}')
    USED_MEM=$(free -m | awk '/Mem:/ {print $3}')
    AVAIL_MEM=$(free -m | awk '/Mem:/ {print $7}')
    echo -e "总内存    : ${TOTAL_MEM} MB"
    echo -e "可用内存  : ${AVAIL_MEM} MB"
    echo -e "已使用    : ${USED_MEM} MB ($((USED_MEM * 100 / TOTAL_MEM))%)"

    # 切换到下一行位置
    tput cup 15 0

    # 打印网络流量
    echo -e "\033[1;32m=========== 网络流量 ===========\033[0m"
    INTERFACE=$(ip -o -4 route show default | awk '{print $5}')
    RX1=$(cat /sys/class/net/$INTERFACE/statistics/rx_bytes)
    TX1=$(cat /sys/class/net/$INTERFACE/statistics/tx_bytes)
    sleep 1
    RX2=$(cat /sys/class/net/$INTERFACE/statistics/rx_bytes)
    TX2=$(cat /sys/class/net/$INTERFACE/statistics/tx_bytes)
    RX_RATE=$(((RX2 - RX1) / 1024))
    TX_RATE=$(((TX2 - TX1) / 1024))
    echo -e "下行速率   : ${RX_RATE} KB/s"
    echo -e "上行速率   : ${TX_RATE} KB/s"

    # 切换到下一行位置
    tput cup 19 0

    # 打印进程资源占用 (TOP 5),去掉 ps 进程
    echo -e "\033[1;32m============= 进程资源占用 (TOP 5) =============\033[0m"
    echo -e "PID      用户     CPU%   MEM%   命令"
    ps -eo pid,user,%cpu,%mem,comm --sort=-%cpu | awk 'NR>1 {if ($1 != 1) printf "%-8s %-8s %-6s %-6s %-15s\n", $1, $2, $3, $4, $5}' | head -n 5

    # 切换到下一行位置
    tput cup 27 0

    # 打印磁盘使用情况
    echo -e "\033[1;32m================== 磁盘使用情况 ====================\033[0m"
    echo -e "挂载点          总大小          剩余空间        使用率"
    df -h --output=target,size,avail,pcent | awk 'NR==1 {next} {printf "%-15s %-15s %-15s %-6s\n", $1, $2, $3, $4}'

    # 刷新
    sleep 5  # 等待 5 秒后刷新,不清屏
    tput cup 0 0 # 刷新时返回屏幕顶部,确保不会重复显示
done
bash monitor.sh
=========== 系统信息 ===========
主机名     : huhy
操作系统   : Ubuntu 24.04 LTS
内核版本   : 6.8.0-31-generic
CPU 型号   : 13th Gen Intel(R) Core(TM) i7-13700
运行时间   : up 5 hours, 22 minutes
当前时间   : 2025-02-07 08:08:10
=========== CPU 信息 ===========
CPU 使用率 : 100%

=========== 内存信息 ===========
总内存    : 3868 MB
可用内存  : 3234 MB
已使用    : 633 MB (16%)

=========== 网络流量 ===========
下行速率   : 0 KB/s
上行速率   : 0 KB/s

============= 进程资源占用 (TOP 5) =============
PID      用户     CPU%   MEM%   命令
49169    root     0.2    0.0    kworker/0:1-mm_percpu_wq
37295    root     0.2    0.0    kworker/1:0-eventscpu_wq
4108     root     0.2    0.0    kworker/2:2-eventscpu_wq
58572    root     0.1    0.0    bash           nts
1924     root     0.1    0.0    kworker/0:3-rcu_par_gp

================== 磁盘使用情况 ====================
挂载点          总大小          剩余空间        使用率
/run            387M            386M            1%
/               48G             40G             15%
/dev/shm        1.9G            1.9G            0%
/run/lock       5.0M            5.0M            0%
/boot           2.0G            1.7G            10%
/run/user/0     387M            387M            1%

在这里插入图片描述

  • 功能特点
    ✅ 适用于大多数Linux服务器
    ✅ 监控数据自动5s刷新
    ✅ 终端窗口运行,自动清屏保持界面整洁。