流程控制是Shell脚本编程的核心,通过条件判断和循环结构,可以实现复杂的逻辑控制。本章将详细介绍Shell脚本中的流程控制语句。
语法格式:
if [ 条件 ]; then
命令
fi
示例:
#!/bin/bash
age=18
# 基本if语句
if [ $age -ge 18 ]; then
echo "成年人"
fi
# 检查文件是否存在
if [ -f "/etc/passwd" ]; then
echo "文件存在"
fi
# 检查目录是否存在
if [ -d "/home" ]; then
echo "目录存在"
fi
# 检查命令是否成功
if ls /etc &> /dev/null; then
echo "命令执行成功"
fi
东巴文提示:if语句以fi结尾,这是Shell脚本的特色。
语法格式:
if [ 条件 ]; then
命令1
else
命令2
fi
示例:
#!/bin/bash
score=75
# if-else语句
if [ $score -ge 60 ]; then
echo "及格"
else
echo "不及格"
fi
# 检查用户是否存在
username="testuser"
if id "$username" &>/dev/null; then
echo "用户 $username 已存在"
else
echo "用户 $username 不存在"
fi
# 检查服务是否运行
service="nginx"
if systemctl is-active --quiet "$service"; then
echo "$service 正在运行"
else
echo "$service 未运行"
fi
语法格式:
if [ 条件1 ]; then
命令1
elif [ 条件2 ]; then
命令2
elif [ 条件3 ]; then
命令3
else
命令4
fi
示例:
#!/bin/bash
score=85
# 成绩等级判断
if [ $score -ge 90 ]; then
echo "优秀"
elif [ $score -ge 80 ]; then
echo "良好"
elif [ $score -ge 70 ]; then
echo "中等"
elif [ $score -ge 60 ]; then
echo "及格"
else
echo "不及格"
fi
# 系统类型判断
if [ -f /etc/debian_version ]; then
echo "Debian/Ubuntu系统"
elif [ -f /etc/redhat-release ]; then
echo "RedHat/CentOS系统"
elif [ -f /etc/arch-release ]; then
echo "Arch Linux系统"
else
echo "未知系统"
fi
# 时间段判断
hour=$(date +%H)
if [ $hour -lt 6 ]; then
echo "凌晨"
elif [ $hour -lt 12 ]; then
echo "上午"
elif [ $hour -lt 14 ]; then
echo "中午"
elif [ $hour -lt 18 ]; then
echo "下午"
else
echo "晚上"
fi
东巴文理解:elif是else if的缩写,用于多条件判断。
test命令等价于[]:
#!/bin/bash
# 使用test命令
if test -f "/etc/passwd"; then
echo "文件存在"
fi
# 等价于
if [ -f "/etc/passwd" ]; then
echo "文件存在"
fi
# test命令选项
test -z "$var" # 字符串长度为0
test -n "$var" # 字符串长度不为0
test "$a" = "$b" # 字符串相等
test "$a" != "$b" # 字符串不相等
test "$a" -eq "$b" # 整数相等
test "$a" -ne "$b" # 整数不相等
test -f "$file" # 文件存在且为普通文件
test -d "$dir" # 目录存在
test -r "$file" # 文件可读
test -w "$file" # 文件可写
test -x "$file" # 文件可执行
[[]]比[]更强大:
#!/bin/bash
# [[]]支持&&和||
if [[ -f "/etc/passwd" && -r "/etc/passwd" ]]; then
echo "文件存在且可读"
fi
# [[]]支持模式匹配
name="test.txt"
if [[ $name == *.txt ]]; then
echo "这是文本文件"
fi
# [[]]支持正则表达式
email="user@example.com"
if [[ $email =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then
echo "邮箱格式正确"
fi
# [[]]不需要转义特殊字符
if [[ $name != "test" ]]; then
echo "名称不是test"
fi
# 对比:[]需要转义
if [ "$name" != "test" ]; then
echo "名称不是test"
fi
东巴文推荐:使用[[]],功能更强大,更安全。
(())用于数值比较:
#!/bin/bash
a=10
b=20
# 使用(())进行数值比较
if (( a < b )); then
echo "$a 小于 $b"
fi
# 使用C风格语法
if (( a > 5 && b < 30 )); then
echo "条件成立"
fi
# 自增自减
count=0
if (( count++ == 0 )); then
echo "count初始值为0"
fi
echo "count现在为:$count"
# 复杂运算
if (( (a + b) > 25 )); then
echo "a + b 大于 25"
fi
语法格式:
case 变量 in
模式1)
命令1
;;
模式2)
命令2
;;
*)
默认命令
;;
esac
示例:
#!/bin/bash
# 菜单选择
echo "请选择操作:"
echo "1. 显示日期"
echo "2. 显示日历"
echo "3. 显示用户"
read -p "请输入选项(1-3):" choice
case $choice in
1)
echo "当前日期:$(date +%Y-%m-%d)"
;;
2)
cal
;;
3)
who
;;
*)
echo "无效选项"
;;
esac
东巴文理解:case语句以esac结尾,每个模式以;;结束。
使用通配符:
#!/bin/bash
# 文件类型判断
filename="test.txt"
case $filename in
*.txt)
echo "文本文件"
;;
*.sh)
echo "Shell脚本"
;;
*.jpg|*.png|*.gif)
echo "图片文件"
;;
*)
echo "未知文件类型"
;;
esac
# 系统判断
case $(uname -s) in
Linux)
echo "Linux系统"
;;
Darwin)
echo "macOS系统"
;;
CYGWIN*|MINGW*)
echo "Windows系统"
;;
*)
echo "未知系统"
;;
esac
# 服务管理
action="start"
case $action in
start|restart)
echo "启动服务"
;;
stop)
echo "停止服务"
;;
status)
echo "查看状态"
;;
*)
echo "用法:$0 {start|stop|restart|status}"
;;
esac
服务管理脚本:
#!/bin/bash
# 服务管理脚本
SERVICE="nginx"
case "$1" in
start)
echo "启动 $SERVICE..."
systemctl start $SERVICE
;;
stop)
echo "停止 $SERVICE..."
systemctl stop $SERVICE
;;
restart)
echo "重启 $SERVICE..."
systemctl restart $SERVICE
;;
status)
systemctl status $SERVICE
;;
*)
echo "用法:$0 {start|stop|restart|status}"
exit 1
;;
esac
用户输入验证:
#!/bin/bash
read -p "请输入yes或no:" answer
case $answer in
y|Y|yes|YES|Yes)
echo "您选择了YES"
;;
n|N|no|NO|No)
echo "您选择了NO"
;;
*)
echo "无效输入"
;;
esac
语法格式:
for 变量 in 列表; do
命令
done
示例:
#!/bin/bash
# 遍历列表
for i in 1 2 3 4 5; do
echo "数字:$i"
done
# 遍历字符串
for name in "东巴文" "张三" "李四"; do
echo "姓名:$name"
done
# 遍历文件
for file in *.txt; do
echo "文件:$file"
done
# 遍历目录
for dir in /home/*; do
if [ -d "$dir" ]; then
echo "目录:$dir"
fi
done
# 遍历命令输出
for user in $(cat /etc/passwd | cut -d: -f1); do
echo "用户:$user"
done
# 遍历数组
arr=("apple" "banana" "orange")
for fruit in "${arr[@]}"; do
echo "水果:$fruit"
done
语法格式:
for (( 初始化; 条件; 更新 )); do
命令
done
示例:
#!/bin/bash
# 基本循环
for (( i=1; i<=5; i++ )); do
echo "计数:$i"
done
# 倒序循环
for (( i=10; i>=1; i-- )); do
echo "倒计时:$i"
done
# 步长循环
for (( i=0; i<=10; i+=2 )); do
echo "偶数:$i"
done
# 嵌套循环
for (( i=1; i<=3; i++ )); do
for (( j=1; j<=3; j++ )); do
echo "i=$i, j=$j"
done
done
# 使用变量
start=1
end=5
for (( i=$start; i<=$end; i++ )); do
echo "数字:$i"
done
东巴文理解:C风格for循环更灵活,适合数值迭代。
批量创建文件:
#!/bin/bash
# 创建100个文件
for i in {1..100}; do
filename="file_${i}.txt"
touch "$filename"
echo "创建文件:$filename"
done
echo "批量创建完成"
批量重命名:
#!/bin/bash
# 重命名所有.txt文件为.bak
for file in *.txt; do
if [ -f "$file" ]; then
newname="${file%.txt}.bak"
mv "$file" "$newname"
echo "重命名:$file -> $newname"
fi
done
批量压缩:
#!/bin/bash
# 压缩所有目录
for dir in */; do
if [ -d "$dir" ]; then
dirname=${dir%/}
tar -czf "${dirname}.tar.gz" "$dirname"
echo "压缩:$dirname"
fi
done
语法格式:
while [ 条件 ]; do
命令
done
示例:
#!/bin/bash
# 基本计数
count=1
while [ $count -le 5 ]; do
echo "计数:$count"
((count++))
done
# 读取文件
while read line; do
echo "行内容:$line"
done < /etc/passwd
# 读取文件并分割字段
while IFS=: read -r username password uid gid info home shell; do
echo "用户:$username, UID:$uid"
done < /etc/passwd
# 无限循环
while true; do
echo "按Ctrl+C退出"
sleep 1
done
# 用户输入循环
while true; do
read -p "请输入数字(q退出):" input
if [ "$input" = "q" ]; then
break
fi
echo "您输入的是:$input"
done
监控脚本:
#!/bin/bash
# 监控CPU使用率
threshold=80
while true; do
cpu_usage=$(top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100 - $1}')
if (( $(echo "$cpu_usage > $threshold" | bc -l) )); then
echo "[警告] CPU使用率:${cpu_usage}%"
# 发送告警邮件
# echo "CPU使用率过高" | mail -s "CPU告警" admin@example.com
fi
sleep 5
done
倒计时脚本:
#!/bin/bash
# 倒计时
seconds=10
while [ $seconds -gt 0 ]; do
echo -ne "倒计时:$seconds秒\r"
sleep 1
((seconds--))
done
echo -e "\n时间到!"
进度条:
#!/bin/bash
# 进度条
total=100
current=0
while [ $current -le $total ]; do
percent=$((current * 100 / total))
bar=$(printf "%-${percent}s" "#" | tr ' ' '#')
printf "\r[%-50s] %d%%" "$bar" "$percent"
sleep 0.1
((current++))
done
echo -e "\n完成!"
语法格式:
until [ 条件 ]; do
命令
done
示例:
#!/bin/bash
# until循环(条件为假时执行)
count=1
until [ $count -gt 5 ]; do
echo "计数:$count"
((count++))
done
# 等待文件创建
file="/tmp/test.txt"
until [ -f "$file" ]; do
echo "等待文件创建..."
sleep 1
done
echo "文件已创建"
# 等待服务启动
until systemctl is-active --quiet nginx; do
echo "等待nginx启动..."
sleep 2
done
echo "nginx已启动"
东巴文理解:until循环与while相反,条件为假时执行循环。
等待网络连接:
#!/bin/bash
# 等待网络连接
until ping -c 1 8.8.8.8 &> /dev/null; do
echo "等待网络连接..."
sleep 2
done
echo "网络已连接"
等待进程结束:
#!/bin/bash
# 等待进程结束
pid=12345
until ! kill -0 $pid 2>/dev/null; do
echo "等待进程 $pid 结束..."
sleep 1
done
echo "进程已结束"
语法格式:
select 变量 in 列表; do
命令
done
示例:
#!/bin/bash
# 菜单选择
PS3="请选择操作系统:" # 设置提示符
select os in "Ubuntu" "CentOS" "Debian" "Arch" "退出"; do
case $os in
"Ubuntu")
echo "您选择了Ubuntu"
;;
"CentOS")
echo "您选择了CentOS"
;;
"Debian")
echo "您选择了Debian"
;;
"Arch")
echo "您选择了Arch Linux"
;;
"退出")
break
;;
*)
echo "无效选项"
;;
esac
done
东巴文理解:select循环自动生成菜单,适合交互式选择。
服务管理菜单:
#!/bin/bash
# 服务管理菜单
PS3="请选择操作:"
select action in "启动服务" "停止服务" "重启服务" "查看状态" "退出"; do
case $action in
"启动服务")
systemctl start nginx
echo "nginx已启动"
;;
"停止服务")
systemctl stop nginx
echo "nginx已停止"
;;
"重启服务")
systemctl restart nginx
echo "nginx已重启"
;;
"查看状态")
systemctl status nginx
;;
"退出")
break
;;
*)
echo "无效选项"
;;
esac
done
break:跳出整个循环
#!/bin/bash
# break示例
for i in {1..10}; do
if [ $i -eq 5 ]; then
echo "遇到5,跳出循环"
break
fi
echo "数字:$i"
done
echo "循环结束"
# 输出:
# 数字:1
# 数字:2
# 数字:3
# 数字:4
# 遇到5,跳出循环
# 循环结束
使用break n跳出n层循环:
#!/bin/bash
# 跳出多层循环
for i in {1..3}; do
for j in {1..3}; do
if [ $i -eq 2 ] && [ $j -eq 2 ]; then
echo "跳出所有循环"
break 2 # 跳出2层循环
fi
echo "i=$i, j=$j"
done
done
echo "所有循环结束"
东巴文理解:break n可以跳出n层嵌套循环。
continue:跳过本次循环,继续下一次
#!/bin/bash
# continue示例
for i in {1..10}; do
if [ $((i % 2)) -eq 0 ]; then
continue # 跳过偶数
fi
echo "奇数:$i"
done
# 输出:
# 奇数:1
# 奇数:3
# 奇数:5
# 奇数:7
# 奇数:9
使用continue n跳过n层循环的本次迭代:
#!/bin/bash
# 跳过多层循环
for i in {1..3}; do
for j in {1..3}; do
if [ $j -eq 2 ]; then
continue 2 # 跳过外层循环的本次迭代
fi
echo "i=$i, j=$j"
done
done
# 输出:
# i=1, j=1
# i=2, j=1
# i=3, j=1
exit:退出整个脚本
#!/bin/bash
# exit示例
for i in {1..10}; do
if [ $i -eq 5 ]; then
echo "遇到5,退出脚本"
exit 1 # 退出脚本,返回状态码1
fi
echo "数字:$i"
done
echo "这行不会执行"
# 输出:
# 数字:1
# 数字:2
# 数字:3
# 数字:4
# 遇到5,退出脚本
使用exit进行错误处理:
#!/bin/bash
# 检查文件是否存在
file="/etc/passwd"
if [ ! -f "$file" ]; then
echo "错误:文件 $file 不存在"
exit 1
fi
# 检查文件是否可读
if [ ! -r "$file" ]; then
echo "错误:文件 $file 不可读"
exit 2
fi
# 检查命令是否存在
if ! command -v grep &> /dev/null; then
echo "错误:grep命令未找到"
exit 3
fi
echo "所有检查通过"
exit 0
东巴文最佳实践:使用不同的退出码表示不同的错误类型。
return:从函数返回
#!/bin/bash
# 定义函数
function check_file() {
local file="$1"
if [ ! -f "$file" ]; then
return 1 # 文件不存在
fi
if [ ! -r "$file" ]; then
return 2 # 文件不可读
fi
return 0 # 成功
}
# 调用函数
check_file "/etc/passwd"
case $? in
0)
echo "文件检查通过"
;;
1)
echo "文件不存在"
;;
2)
echo "文件不可读"
;;
esac
东巴文理解:return只能在函数中使用,用于返回函数状态。
方式一:使用function关键字:
function 函数名() {
命令
}
方式二:省略function关键字:
函数名() {
命令
}
示例:
#!/bin/bash
# 方式一
function hello() {
echo "Hello, World!"
}
# 方式二
bye() {
echo "Goodbye!"
}
# 调用函数
hello
bye
东巴文推荐:使用方式一,更清晰。
函数参数传递:
#!/bin/bash
# 定义带参数的函数
function greet() {
local name="$1"
local age="$2"
echo "姓名:$name"
echo "年龄:$age"
}
# 调用函数并传递参数
greet "东巴文" 25
# 输出:
# 姓名:东巴文
# 年龄:25
参数处理:
#!/bin/bash
# 参数处理函数
function show_params() {
echo "函数名:$0"
echo "第一个参数:$1"
echo "第二个参数:$2"
echo "参数个数:$#"
echo "所有参数:$@"
# 遍历所有参数
for param in "$@"; do
echo "参数:$param"
done
}
# 调用函数
show_params a b c d
东巴文提示:函数内的$1、$2等表示函数参数,不是脚本参数。
return返回状态码:
#!/bin/bash
# 检查文件是否存在
function file_exists() {
local file="$1"
if [ -f "$file" ]; then
return 0 # 存在
else
return 1 # 不存在
fi
}
# 调用函数
if file_exists "/etc/passwd"; then
echo "文件存在"
else
echo "文件不存在"
fi
echo返回字符串:
#!/bin/bash
# 获取文件大小
function get_file_size() {
local file="$1"
if [ -f "$file" ]; then
local size=$(du -h "$file" | cut -f1)
echo "$size"
else
echo "0"
fi
}
# 调用函数并获取返回值
size=$(get_file_size "/etc/passwd")
echo "文件大小:$size"
东巴文理解:return返回状态码,echo返回字符串。
使用local定义局部变量:
#!/bin/bash
# 全局变量
global_var="全局变量"
function test_local() {
# 局部变量
local local_var="局部变量"
echo "函数内 - global_var: $global_var"
echo "函数内 - local_var: $local_var"
}
# 调用函数
test_local
echo "函数外 - global_var: $global_var"
echo "函数外 - local_var: $local_var" # 空,因为局部变量在函数外不可见
# 输出:
# 函数内 - global_var: 全局变量
# 函数内 - local_var: 局部变量
# 函数外 - global_var: 全局变量
# 函数外 - local_var:
东巴文最佳实践:函数内的变量尽量使用local,避免污染全局命名空间。
计算阶乘:
#!/bin/bash
# 计算阶乘
function factorial() {
local n=$1
if [ $n -le 1 ]; then
echo 1
else
local prev=$(factorial $((n - 1)))
echo $((n * prev))
fi
}
# 调用函数
result=$(factorial 5)
echo "5! = $result"
# 输出:5! = 120
斐波那契数列:
#!/bin/bash
# 斐波那契数列
function fibonacci() {
local n=$1
if [ $n -le 1 ]; then
echo $n
else
local a=$(fibonacci $((n - 1)))
local b=$(fibonacci $((n - 2)))
echo $((a + b))
fi
}
# 调用函数
for i in {0..10}; do
result=$(fibonacci $i)
echo "fib($i) = $result"
done
东巴文提示:递归函数要注意终止条件,避免无限递归。
创建函数库文件:
#!/bin/bash
# 函数库:utils.sh
# 日志函数
function log_info() {
echo "[INFO] $(date '+%Y-%m-%d %H:%M:%S') $1"
}
function log_error() {
echo "[ERROR] $(date '+%Y-%m-%d %H:%M:%S') $1" >&2
}
# 检查文件
function check_file() {
local file="$1"
if [ ! -f "$file" ]; then
log_error "文件不存在:$file"
return 1
fi
if [ ! -r "$file" ]; then
log_error "文件不可读:$file"
return 2
fi
log_info "文件检查通过:$file"
return 0
}
# 备份文件
function backup_file() {
local file="$1"
local backup_dir="${2:-/backup}"
local backup_file="${backup_dir}/$(basename $file).$(date +%Y%m%d_%H%M%S)"
if [ ! -d "$backup_dir" ]; then
mkdir -p "$backup_dir"
fi
cp "$file" "$backup_file"
log_info "备份完成:$backup_file"
}
在脚本中引用函数库:
#!/bin/bash
# 引入函数库
source ./utils.sh
# 或使用点命令
. ./utils.sh
# 使用函数库中的函数
log_info "脚本开始执行"
check_file "/etc/passwd"
if [ $? -eq 0 ]; then
backup_file "/etc/passwd"
fi
log_info "脚本执行完成"
东巴文最佳实践:将常用函数封装成库,提高代码复用性。
#!/bin/bash
#===============================================================================
# 脚本名称:monitor.sh
# 脚本功能:系统监控脚本
# 作者:东巴文
# 创建日期:2024-01-01
#===============================================================================
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# 阈值设置
CPU_THRESHOLD=80
MEM_THRESHOLD=80
DISK_THRESHOLD=80
# 日志函数
function log() {
echo -e "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}
# 检查CPU使用率
function check_cpu() {
local cpu_usage=$(top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100 - $1}')
if (( $(echo "$cpu_usage > $CPU_THRESHOLD" | bc -l) )); then
log "${RED}[警告] CPU使用率:${cpu_usage}%${NC}"
return 1
else
log "${GREEN}[正常] CPU使用率:${cpu_usage}%${NC}"
return 0
fi
}
# 检查内存使用率
function check_memory() {
local mem_usage=$(free | awk '/Mem/{printf("%.1f"), $3/$2*100}')
if (( $(echo "$mem_usage > $MEM_THRESHOLD" | bc -l) )); then
log "${RED}[警告] 内存使用率:${mem_usage}%${NC}"
return 1
else
log "${GREEN}[正常] 内存使用率:${mem_usage}%${NC}"
return 0
fi
}
# 检查磁盘使用率
function check_disk() {
local disk_usage=$(df -h / | awk 'NR==2{print $5}' | sed 's/%//')
if [ $disk_usage -gt $DISK_THRESHOLD ]; then
log "${RED}[警告] 磁盘使用率:${disk_usage}%${NC}"
return 1
else
log "${GREEN}[正常] 磁盘使用率:${disk_usage}%${NC}"
return 0
fi
}
# 检查服务状态
function check_service() {
local service="$1"
if systemctl is-active --quiet "$service"; then
log "${GREEN}[正常] 服务 $service 正在运行${NC}"
return 0
else
log "${RED}[警告] 服务 $service 未运行${NC}"
return 1
fi
}
# 主函数
function main() {
log "开始系统监控..."
# 检查CPU
check_cpu
# 检查内存
check_memory
# 检查磁盘
check_disk
# 检查关键服务
check_service "nginx"
check_service "mysql"
log "系统监控完成"
}
# 执行主函数
main
#!/bin/bash
#===============================================================================
# 脚本名称:batch_process.sh
# 脚本功能:批量处理文件
# 作者:东巴文
# 创建日期:2024-01-01
#===============================================================================
# 颜色定义
GREEN='\033[0;32m'
NC='\033[0m'
# 统计变量
total_files=0
success_count=0
fail_count=0
# 日志函数
function log() {
echo -e "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}
# 处理单个文件
function process_file() {
local file="$1"
# 检查文件是否存在
if [ ! -f "$file" ]; then
log "文件不存在:$file"
return 1
fi
# 处理文件(示例:统计行数)
local lines=$(wc -l < "$file")
log "处理文件:$file (${lines}行)"
return 0
}
# 批量处理
function batch_process() {
local dir="$1"
local pattern="$2"
log "开始批量处理..."
log "目录:$dir"
log "模式:$pattern"
# 遍历文件
for file in "$dir"/$pattern; do
if [ -f "$file" ]; then
((total_files++))
if process_file "$file"; then
((success_count++))
echo -e "${GREEN}[成功]${NC} $file"
else
((fail_count++))
echo -e "${RED}[失败]${NC} $file"
fi
fi
done
# 显示统计
echo
log "处理完成"
echo "总文件数:$total_files"
echo "成功:$success_count"
echo "失败:$fail_count"
}
# 主函数
function main() {
local target_dir="${1:-.}"
local file_pattern="${2:-*.txt}"
batch_process "$target_dir" "$file_pattern"
}
# 执行主函数
main "$@"
#!/bin/bash
#===============================================================================
# 脚本名称:user_manager.sh
# 脚本功能:用户管理脚本
# 作者:东巴文
# 创建日期:2024-01-01
#===============================================================================
# 检查root权限
if [ "$EUID" -ne 0 ]; then
echo "请使用root用户执行此脚本"
exit 1
fi
# 颜色定义
GREEN='\033[0;32m'
RED='\033[0;31m'
NC='\033[0m'
# 创建用户
function create_user() {
local username="$1"
local password="$2"
# 检查用户是否存在
if id "$username" &>/dev/null; then
echo -e "${RED}用户 $username 已存在${NC}"
return 1
fi
# 创建用户
useradd -m -s /bin/bash "$username"
# 设置密码
echo "$username:$password" | chpasswd
# 设置首次登录修改密码
chage -d 0 "$username"
echo -e "${GREEN}用户 $username 创建成功${NC}"
return 0
}
# 删除用户
function delete_user() {
local username="$1"
# 检查用户是否存在
if ! id "$username" &>/dev/null; then
echo -e "${RED}用户 $username 不存在${NC}"
return 1
fi
# 删除用户
userdel -r "$username"
echo -e "${GREEN}用户 $username 删除成功${NC}"
return 0
}
# 修改密码
function change_password() {
local username="$1"
local password="$2"
# 检查用户是否存在
if ! id "$username" &>/dev/null; then
echo -e "${RED}用户 $username 不存在${NC}"
return 1
fi
# 修改密码
echo "$username:$password" | chpasswd
echo -e "${GREEN}用户 $username 密码修改成功${NC}"
return 0
}
# 列出用户
function list_users() {
echo "系统用户列表:"
echo "----------------------------------------"
printf "%-20s %-10s %-10s\n" "用户名" "UID" "Shell"
echo "----------------------------------------"
while IFS=: read -r username _ uid _ _ _ shell; do
if [ "$uid" -ge 1000 ]; then
printf "%-20s %-10s %-10s\n" "$username" "$uid" "$(basename $shell)"
fi
done < /etc/passwd
}
# 主菜单
function show_menu() {
clear
echo "================================"
echo " 用户管理脚本"
echo "================================"
echo "1. 创建用户"
echo "2. 删除用户"
echo "3. 修改密码"
echo "4. 列出用户"
echo "5. 退出"
echo "================================"
}
# 主函数
function main() {
while true; do
show_menu
read -p "请选择操作(1-5):" choice
case $choice in
1)
read -p "请输入用户名:" username
read -s -p "请输入密码:" password
echo
create_user "$username" "$password"
;;
2)
read -p "请输入用户名:" username
delete_user "$username"
;;
3)
read -p "请输入用户名:" username
read -s -p "请输入新密码:" password
echo
change_password "$username" "$password"
;;
4)
list_users
;;
5)
echo "退出系统"
exit 0
;;
*)
echo -e "${RED}无效选项${NC}"
;;
esac
echo
read -p "按回车继续..."
done
}
# 执行主函数
main
✅ 掌握条件判断语句 ✅ 熟练使用循环结构 ✅ 理解循环控制语句 ✅ 学会函数定义与使用
完成本章学习后,请确认您能够:
东巴文(db-w.cn) - 让Linux学习更简单