Shell 是 Linux 和 Unix 系统中的 命令解释器(Command Interpreter),它是用户与操作系统之间的桥梁,允许用户输入命令来控制计算机的行为。Shell 既可以用于 交互式操作(输入命令后立即执行),也可以用于编写 Shell 脚本,实现自动化任务。
不同的 Linux 发行版可能使用不同的 Shell,最常见的有:
通过以下命令查看当前使用的 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 可能有区别:
直接执行脚本 ./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 变量用于存储数据,分为本地变量和环境变量。
示例
#!/bin/bash
NAME='huhy'
示例
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
#!/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
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
变量 | 作用 |
---|---|
$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
运算符 | 作用 | 示例 |
---|---|---|
十 | 加法 | 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
运算符 | 作用 | 示例 |
---|---|---|
-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
条件满足
运算符 | 作用 | 示例 |
---|---|---|
-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
文件存在
运算符 | 作用 | 示例 |
---|---|---|
= | 等于 | [ “ 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)条件判断
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 变量为空
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 $变量 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 变量 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 [ 条件 ]; do
命令
done
示例
root@huhy:~# cat test.sh
#!/bin/bash
count=1
while [ "$count" -le 5 ]; do
echo "第 $count 次循环"
((count++))
done
root@huhy:~# bash test.sh
第 1 次循环
第 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 [ 条件 ]; do
命令
done
示例
root@huhy:~# cat test.sh
#!/bin/bash
count=1
until [ "$count" -gt 5 ]; do
echo "第 $count 次循环"
((count++))
done
root@huhy:~# bash test.sh
第 1 次循环
第 2 次循环
第 3 次循环
第 4 次循环
第 5 次循环
应用场景:等待某个事件发生、反向控制逻辑
示例: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.
使用 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
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)进程管理
进程管理用于控制脚本或程序的运行状态,包括前台、后台、挂起、终止等操作
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]
---------
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
使用 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
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
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
常用文本提取
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
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
root@huhy:~# awk -F: '/model name/ {print $2; exit}' /proc/cpuinfo
13th Gen Intel(R) Core(TM) i7-13700
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%