Linux Shell 脚本中的 for 循环语句
在 Linux 世界中,Shell 脚本是系统管理员和开发者不可或缺的利器。而其中的 for 循环语句,作为流程控制结构的核心之一,为我们提供了强大的批量处理能力。
什么是 Shell 中的 for 循环?
在 Shell 脚本中, 循环是一种用于重复执行一段代码块的控制结构。它允许我们遍历一组值(如数字序列、文件列表、命令输出等),并对每个值执行相同或相似的操作。
Shell 脚本 for 循环用于重复执行代码块,支持列表遍历、通配符匹配及 C 风格语法。文章详解基础语法、批量文件处理、系统监控及数据库备份等应用场景,并与 Java 进行对比以建立跨语言思维模型。同时涵盖性能优化、错误处理、安全实践及与 Docker 和 Kubernetes 的集成方案,提供自动化运维参考。

在 Linux 世界中,Shell 脚本是系统管理员和开发者不可或缺的利器。而其中的 for 循环语句,作为流程控制结构的核心之一,为我们提供了强大的批量处理能力。
在 Shell 脚本中, 循环是一种用于重复执行一段代码块的控制结构。它允许我们遍历一组值(如数字序列、文件列表、命令输出等),并对每个值执行相同或相似的操作。
for最基本的 for 循环语法如下:
for variable in list do commands done
这里的 variable 是循环变量,list 是要遍历的值列表,commands 是每次迭代要执行的命令集合。
让我们从一个最简单的例子开始:
#!/bin/bash
for i in 1 2 3 4 5
do
echo "当前数字:$i"
done
运行结果:
当前数字:1
当前数字:2
当前数字:3
当前数字:4
当前数字:5
这是最直观的形式,直接列出要遍历的所有值:
#!/bin/bash
for fruit in apple banana orange grape
do
echo "我喜欢吃 $fruit"
done
Shell 的强大之处在于可以直接使用通配符来匹配文件:
#!/bin/bash
echo "当前目录下的 .txt 文件:"
for file in *.txt
do
if [ -f "$file" ]; then
echo "文件名:$file"
wc -l "$file" # 统计行数
fi
done
Bash 还支持类似 C 语言的 for 循环语法:
#!/bin/bash
for ((i=1; i<=10; i++))
do
echo "第 $i 次迭代"
done
这种语法特别适合需要精确控制循环次数和步长的场景。
seq 命令可以生成数字序列,常与 for 循环配合使用:
#!/bin/bash
# 生成 1 到 10 的序列
for i in $(seq 1 10)
do
echo "数字:$i"
done
echo "---"
# 生成 0 到 10,步长为 2 的序列
for i in $(seq 0 2 10)
do
echo "偶数:$i"
done
假设我们需要对目录下所有图片文件进行重命名:
#!/bin/bash
counter=1
for image in *.jpg *.png *.gif
do
if [ -f "$image" ]; then
extension="${image##*.}"
new_name="photo_${counter}.${extension}"
mv "$image" "$new_name"
echo "已重命名:$image -> $new_name"
((counter++))
fi
done
创建一个简单的系统监控脚本,定期检查多个服务的状态:
#!/bin/bash
services=("nginx" "mysql" "redis" "apache2")
echo "=== 服务状态检查 ==="
for service in "${services[@]}"
do
if systemctl is-active --quiet "$service"; then
echo "✅ $service 正在运行"
else
echo "❌ $service 未运行"
# 可以在这里添加自动重启逻辑
# sudo systemctl start $service
fi
done
自动化备份多个数据库:
#!/bin/bash
databases=("users_db" "products_db" "orders_db" "logs_db")
backup_dir="/backups/$(date +%Y%m%d)"
mkdir -p "$backup_dir"
for db in "${databases[@]}"
do
backup_file="$backup_dir/${db}_$(date +%H%M%S).sql"
mysqldump -u root -p"$MYSQL_PASSWORD" "$db" > "$backup_file"
if [ $? -eq 0 ]; then
echo "✅ $db 备份成功:$backup_file"
gzip "$backup_file"
else
echo "❌ $db 备份失败"
fi
done
为了更好地理解 Shell 中的 for 循环,让我们将其与 Java 中的对应结构进行对比。
Shell 版本:
#!/bin/bash
for i in 1 2 3 4 5
do
echo "数字:$i"
done
Java 版本:
public class ForLoopExample {
public static void main(String[] args) {
for (int i = 1; i <= 5; i++) {
System.out.println("数字:" + i);
}
}
}
Shell 版本:
#!/bin/bash
fruits=("apple" "banana" "orange" "grape")
for fruit in "${fruits[@]}"
do
echo "水果:$fruit"
done
Java 版本:
public class ArrayTraversal {
public static void main(String[] args) {
String[] fruits = {"apple", "banana", "orange", "grape"};
// 使用传统 for 循环
for (int i = 0; i < fruits.length; i++) {
System.out.println("水果:" + fruits[i]);
}
System.out.println("---");
// 使用增强型 for 循环
for (String fruit : fruits) {
System.out.println("水果:" + fruit);
}
}
}
Shell 版本:
#!/bin/bash
for file in *.txt
do
if [ -f "$file" ]; then
echo "处理文件:$file"
wc -l "$file"
fi
done
Java 版本:
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
public class FileProcessing {
public static void main(String[] args) {
File directory = new File(".");
File[] txtFiles = directory.listFiles((dir, name) -> name.endsWith(".txt"));
if (txtFiles != null) {
for (File file : txtFiles) {
if (file.isFile()) {
System.out.println("处理文件:" + file.getName());
try {
long lineCount = Files.lines(Paths.get(file.getAbsolutePath())).count();
System.out.println("行数:" + lineCount);
} catch (IOException e) {
System.err.println("读取文件失败:" + e.getMessage());
}
}
}
}
}
}
Shell 版本(使用关联数组):
#!/bin/bash
declare -A student_scores
student_scores["张三"]=85
student_scores["李四"]=92
student_scores["王五"]=78
student_scores["赵六"]=96
echo "学生成绩统计:"
for student in "${!student_scores[@]}"
do
score=${student_scores[$student]}
grade=""
if [ $score -ge 90 ]; then
grade="A"
elif [ $score -ge 80 ]; then
grade="B"
elif [ $score -ge 70 ]; then
grade="C"
else
grade="D"
fi
echo "$student: $score 分 - $grade 等级"
done
Java 版本:
import java.util.HashMap;
import java.util.Map;
public class StudentGrades {
public static void main(String[] args) {
Map<String, Integer> studentScores = new HashMap<>();
studentScores.put("张三", 85);
studentScores.put("李四", 92);
studentScores.put("王五", 78);
studentScores.put("赵六", 96);
System.out.println("学生成绩统计:");
for (Map.Entry<String, Integer> entry : studentScores.entrySet()) {
String student = entry.getKey();
int score = entry.getValue();
String grade;
if (score >= 90) {
grade = "A";
} else if (score >= 80) {
grade = "B";
} else if (score >= 70) {
grade = "C";
} else {
grade = "D";
}
System.out.println(student + ": " + score + " 分 - " + grade + " 等级");
}
}
}
#!/bin/bash
# 默认情况下,IFS 包含空格、制表符和换行符
data="apple,banana,orange,grape"
OLD_IFS=$IFS
IFS=','
for item in $data
do
echo "水果:$item"
done
# 恢复原始 IFS
IFS=$OLD_IFS
#!/bin/bash
echo "九九乘法表:"
for i in {1..9}
do
for j in {1..9}
do
if [ $j -le $i ]; then
printf "%d×%d=%-2d " $j $i $((i*j))
fi
done
echo
done
#!/bin/bash
echo "查找第一个能被 7 整除的数字:"
for i in {1..100}
do
if [ $((i % 7)) -eq 0 ]; then
echo "找到:$i"
break
fi
done
echo "---"
echo "跳过能被 3 整除的数字:"
for i in {1..20}
do
if [ $((i % 3)) -eq 0 ]; then
continue
fi
echo "$i "
done
#!/bin/bash
max_jobs=4
job_count=0
files=("file1.txt" "file2.txt" "file3.txt" "file4.txt" "file5.txt")
for file in "${files[@]}"
do
# 后台执行任务
process_file() {
local f=$1
echo "开始处理 $f"
sleep 2 # 模拟处理时间
echo "完成处理 $f"
}
process_file "$file" &
((job_count++))
if [ $job_count -ge $max_jobs ]; then
wait # 等待当前批次完成
job_count=0
fi
done
wait # 等待所有后台任务完成
echo "所有文件处理完成!"
#!/bin/bash
# ❌ 不推荐:每次迭代都调用外部命令
for i in {1..1000}
do
current_date=$(date)
echo "处理第 $i 项 - $current_date"
done
# ✅ 推荐:在循环外获取一次
current_date=$(date)
for i in {1..1000}
do
echo "处理第 $i 项 - $current_date"
done
#!/bin/bash
# ❌ 较慢:使用外部命令 expr
for i in {1..1000}
do
result=$(expr $i \* 2)
done
# ✅ 较快:使用 Shell 内置算术扩展
for i in {1..1000}
do
result=$((i * 2))
done
#!/bin/bash
# ❌ 逐个删除文件
for file in *.log
do
rm "$file"
done
# ✅ 批量删除(更高效)
rm *.log
#!/bin/bash
set -e # 遇到错误时退出
files=("important.txt" "critical.txt" "essential.txt")
for file in "${files[@]}"
do
if [ ! -f "$file" ]; then
echo "⚠️ 警告:文件 $file 不存在" >&2
continue
fi
if ! cp "$file" "${file}.bak"; then
echo "❌ 错误:无法备份文件 $file" >&2
exit 1
fi
echo "✅ 成功备份:$file"
done
#!/bin/bash
# 启用调试模式
set -x
for i in {1..5}
do
echo "迭代 $i"
result=$((i * i))
echo "平方:$result"
done
# 关闭调试模式
set +x
#!/bin/bash
LOG_FILE="/var/log/my_script.log"
log_message() {
local level=$1
local message=$2
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$timestamp] [$level] $message" | tee -a "$LOG_FILE"
}
directories=("/home/user/docs" "/home/user/pictures" "/home/user/music")
for dir in "${directories[@]}"
do
if [ -d "$dir" ]; then
file_count=$(find "$dir" -type f | wc -l)
log_message "INFO" "目录 $dir 包含 $file_count 个文件"
else
log_message "WARNING" "目录 $dir 不存在"
fi
done
#!/bin/bash
# 配置变量
APP_NAME="my-web-app"
VERSION="1.0.0"
SERVERS=("server1.example.com" "server2.example.com" "server3.example.com")
DEPLOY_DIR="/opt/$APP_NAME"
BACKUP_DIR="/backup/$APP_NAME"
# 函数定义
deploy_to_server() {
local server=$1
local version=$2
echo "🚀 开始部署到 $server"
# 创建备份目录
ssh "$server" "mkdir -p $BACKUP_DIR"
# 备份现有应用
if ssh "$server" "[ -d $DEPLOY_DIR ]"; then
backup_name="${APP_NAME}_$(date +%Y%m%d_%H%M%S)"
ssh "$server" "cp -r $DEPLOY_DIR $BACKUP_DIR/$backup_name"
echo "✅ 已备份现有应用到 $BACKUP_DIR/$backup_name"
fi
# 传输新版本
scp -r "./build/$APP_NAME-$version" "$server:$DEPLOY_DIR"
# 设置权限
ssh "$server" "chown -R www-data:www-data $DEPLOY_DIR"
ssh "$server" "chmod -R 755 $DEPLOY_DIR"
# 重启服务
ssh "$server" "systemctl restart $APP_NAME"
# 验证部署
if ssh "$server" "systemctl is-active $APP_NAME" >/dev/null 2>&1; then
echo "🎉 部署成功:$server"
return 0
else
echo "❌ 部署失败:$server"
return 1
fi
}
# 主部署循环
echo "📦 开始部署 $APP_NAME 版本 $VERSION"
success_count=0
for server in "${SERVERS[@]}"
do
if deploy_to_server "$server" "$VERSION"; then
((success_count++))
else
echo "⚠️ 跳过后续服务器,因为 $server 部署失败"
break
fi
done
echo "📊 部署统计:$success_count/${#SERVERS[@]} 台服务器成功"
if [ $success_count -eq ${#SERVERS[@]} ]; then
echo "✅ 所有服务器部署成功!"
exit 0
else
echo "❌ 部分服务器部署失败!"
exit 1
fi
#!/bin/bash
# 数据分析脚本 - 分析销售数据
DATA_DIR="./sales_data"
REPORT_DIR="./reports"
CURRENT_DATE=$(date +%Y%m%d)
mkdir -p "$REPORT_DIR"
# 获取所有数据文件
data_files=("$DATA_DIR"/*.csv)
if [ ${#data_files[@]} -eq 0 ] || [ ! -f "${data_files[0]}" ]; then
echo "❌ 没有找到销售数据文件"
exit 1
fi
echo "📈 开始分析销售数据..."
# 初始化汇总变量
total_sales=0
total_transactions=0
best_seller=""
max_sales=0
# 分析每个文件
for file in "${data_files[@]}"
do
if [ ! -f "$file" ]; then
continue
fi
echo "📄 处理文件:$(basename "$file")"
# 跳过标题行,计算总销售额和交易数
while IFS=',' read -r product quantity price date
do
# 跳过标题行
if [ "$product" == "Product" ]; then
continue
fi
# 计算单笔交易金额
sale_amount=$(awk "BEGIN {printf \"%.2f\", $quantity * $price}")
# 更新汇总数据
total_sales=$(awk "BEGIN {printf \"%.2f\", $total_sales + $sale_amount}")
((total_transactions++))
# 更新最佳销售产品
if (( $(echo "$sale_amount > $max_sales" | bc -l) )); then
max_sales=$sale_amount
best_seller="$product"
fi
done < "$file"
done
# 生成报告
REPORT_FILE="$REPORT_DIR/sales_report_$CURRENT_DATE.txt"
{
echo "📊 销售数据分析报告"
echo "📅 生成日期:$(date)"
echo ""
echo "💰 总销售额:\$$total_sales"
echo "🛒 总交易数:$total_transactions"
echo "🏆 最佳销售产品:$best_seller (\$$max_sales)"
if [ $total_transactions -gt 0 ]; then
avg_sale=$(awk "BEGIN {printf \"%.2f\", $total_sales / $total_transactions}")
echo "📈 平均每笔交易额:\$$avg_sale"
fi
echo ""
echo "📈 详细数据:"
# 按产品汇总销售数据
declare -A product_sales
declare -A product_counts
for file in "${data_files[@]}"
do
if [ ! -f "$file" ]; then
continue
fi
while IFS=',' read -r product quantity price date
do
if [ "$product" == "Product" ]; then
continue
fi
sale_amount=$(awk "BEGIN {printf \"%.2f\", $quantity * $price}")
if [ -z "${product_sales[$product]}" ]; then
product_sales[$product]=0
product_counts[$product]=0
fi
product_sales[$product]=$(awk "BEGIN {printf \"%.2f\", ${product_sales[$product]} + $sale_amount}")
((product_counts[$product]++))
done < "$file"
done
# 输出产品销售排名
echo "🏆 产品销售排行榜:"
for product in "${!product_sales[@]}"
do
echo " $product: ${product_sales[$product]} (${product_counts[$product]} 笔交易)"
done | sort -t '$' -k2 -nr
} > "$REPORT_FILE"
echo "✅ 报告已生成:$REPORT_FILE"
echo "📁 报告内容:"
cat "$REPORT_FILE"
除了 for 循环,Shell 脚本还提供了 while 和 until 循环。了解它们的区别有助于选择最适合的循环结构。
#!/bin/bash
echo "=== for 循环示例 ==="
for i in {1..5}
do
echo "for 循环:$i"
done
echo "=== while 循环示例 ==="
i=1
while [ $i -le 5 ]
do
echo "while 循环:$i"
((i++))
done
#!/bin/bash
# 场景 1:已知要遍历的元素列表 - 使用 for 循环
echo "🍎 水果列表:"
fruits=("apple" "banana" "orange" "grape")
for fruit in "${fruits[@]}"
do
echo "- $fruit"
done
echo ""
# 场景 2:条件驱动的循环 - 使用 while 循环
echo "🔄 用户输入处理:"
echo "请输入数字(输入 'quit' 退出):"
while true
do
read -p "> " input
if [ "$input" = "quit" ]; then
break
elif [[ "$input" =~ ^[0-9]+$ ]]; then
echo "您输入了数字:$input"
else
echo "请输入有效数字或 'quit'"
fi
done
echo ""
# 场景 3:处理文件行 - 两种方式都可以
echo "📄 文件内容处理:"
# 方式 1:使用 while 循环(推荐用于大文件)
echo "使用 while 循环:"
while IFS= read -r line
do
echo "行:$line"
done < sample.txt
echo ""
# 方式 2:使用 for 循环(适用于小文件)
echo "使用 for 循环:"
lines=$(cat sample.txt)
for line in $lines
do
echo "行:$line"
done
#!/bin/bash
# ❌ 错误做法:文件名包含空格时会出错
for file in $(ls)
do
echo "处理:$file"
done
# ✅ 正确做法:使用通配符并正确引用变量
for file in *
do
if [ -f "$file" ]; then
echo "处理:$file"
fi
done
# ✅ 更好的做法:使用 find 命令
while IFS= read -r -d '' file
do
echo "处理:$file"
done < <(find . -maxdepth 1 -type f -print0)
#!/bin/bash
# ❌ 错误:这样只会遍历第一个元素
array=("item 1" "item 2" "item 3")
for item in $array
do
echo "$item"
done
# ✅ 正确:使用 "${array[@]}"
for item in "${array[@]}"
do
echo "$item"
done
# ✅ 正确:如果需要索引
for i in "${!array[@]}"
do
echo "索引 $i: ${array[i]}"
done
#!/bin/bash
# ❌ 在管道中修改变量不会影响外部
counter=0
echo -e "line1\nline2\nline3" | while read line
do
((counter++))
echo "处理:$line"
done
echo "总计:$counter" # 输出 0,不是期望的 3
# ✅ 解决方案 1:使用重定向而非管道
counter=0
while read line
do
((counter++))
echo "处理:$line"
done < <(echo -e "line1\nline2\nline3")
echo "总计:$counter" # 输出 3
# ✅ 解决方案 2:将逻辑移到函数中
process_lines() {
local count=0
while read line
do
((count++))
echo "处理:$line"
done
echo $count
}
counter=$(echo -e "line1\nline2\nline3" | process_lines)
echo "总计:$counter" # 输出 3
#!/bin/bash
# 使用 for 循环配合 awk 进行复杂文本处理
echo "📊 销售数据分析:"
for file in sales_*.csv
do
if [ -f "$file" ]; then
echo "📁 处理文件:$file"
# 使用 awk 计算总销售额
total=$(awk -F',' 'NR>1 {sum += $2 * $3} END {printf "%.2f", sum}' "$file")
# 使用 awk 找出最高单价的产品
top_product=$(awk -F',' 'NR>1 && $3>max {max=$3; product=$1} END {print product}' "$file")
echo "💰 总销售额:\$$total"
echo "🏆 最高单价产品:$top_product"
echo "---"
fi
done
#!/bin/bash
# 批量文本替换
echo "🔄 批量文本替换:"
extensions=("html" "css" "js")
old_text="old-domain.com"
new_text="new-domain.com"
for ext in "${extensions[@]}"
do
for file in *."$ext"
do
if [ -f "$file" ]; then
echo "📝 处理:$file"
# 使用 sed 进行替换
sed -i "s/$old_text/$new_text/g" "$file"
fi
done
done
echo "✅ 所有文件处理完成!"
#!/bin/bash
# 日志分析脚本
echo "🔍 日志分析:"
log_files=("app.log" "error.log" "access.log")
search_patterns=("ERROR" "WARNING" "CRITICAL")
for log_file in "${log_files[@]}"
do
if [ -f "$log_file" ]; then
echo "📄 分析日志文件:$log_file"
for pattern in "${search_patterns[@]}"
do
count=$(grep -c "$pattern" "$log_file")
if [ $count -gt 0 ]; then
echo " $pattern: $count 次"
# 显示前 3 个匹配行
echo " 示例:"
grep "$pattern" "$log_file" | head -3 | sed 's/^/ /'
fi
done
echo "---"
fi
done
虽然本文主要关注 Linux Shell,但在编写脚本时也需要考虑跨平台兼容性。
#!/bin/bash
# 或者为了更好的兼容性使用:#!/bin/sh
# Bash 特性(可能不兼容 POSIX)
for ((i=0; i<10; i++)); do
echo $i
done
# POSIX 兼容版本
i=0
while [ $i -lt 10 ]; do
echo $i
i=$((i + 1))
done
#!/bin/bash
# 检测系统类型
OS=$(uname -s)
case $OS in
Linux*) DATE_CMD="date -d";;
Darwin*) # macOS
DATE_CMD="date -j -f";;
*)
echo "不支持的操作系统:$OS"
exit 1
;;
esac
# 根据系统选择适当的命令
for day in {1..7}
do
case $OS in
Linux*) formatted_date=$(date -d "$day days ago" +%Y-%m-%d);;
Darwin*) formatted_date=$(date -j -v-${day}d +%Y-%m-%d);;
esac
echo "日期:$formatted_date"
done
#!/bin/bash
# 简单的测试框架
test_count=0
pass_count=0
assert_equal() {
local expected="$1"
local actual="$2"
local message="$3"
((test_count++))
if [ "$expected" = "$actual" ]; then
echo "✅ PASS: $message"
((pass_count++))
else
echo "❌ FAIL: $message"
echo " 期望:'$expected'"
echo " 实际:'$actual'"
fi
}
# 测试 for 循环功能
test_for_loop_basic() {
result=""
for i in 1 2 3
do
result="$result$i"
done
assert_equal "123" "$result" "基本 for 循环"
}
test_array_iteration() {
arr=("a" "b" "c")
result=""
for item in "${arr[@]}"
do
result="$result$item"
done
assert_equal "abc" "$result" "数组遍历"
}
# 运行所有测试
echo "🧪 运行测试套件..."
test_for_loop_basic
test_array_iteration
echo "📊 测试结果:$pass_count/$test_count 通过"
if [ $pass_count -eq $test_count ]; then
echo "🎉 所有测试通过!"
exit 0
else
echo "❌ 存在失败的测试!"
exit 1
fi
#!/bin/bash
benchmark_for_loops() {
local iterations=10000
echo "⏱️ 性能基准测试 ($iterations 次迭代)"
echo ""
# 测试方法 1:C 风格 for 循环
start_time=$(date +%s%3N)
for ((i=0; i<iterations; i++)); do
:
done
end_time=$(date +%s%3N)
c_style_time=$((end_time - start_time))
echo "C 风格 for 循环:${c_style_time}ms"
# 测试方法 2:列表 for 循环
start_time=$(date +%s%3N)
for i in $(seq 1 $iterations); do
:
done
end_time=$(date +%s%3N)
list_style_time=$((end_time - start_time))
echo "列表 for 循环:${list_style_time}ms"
# 测试方法 3:while 循环
start_time=$(date +%s%3N)
i=0
while [ $i -lt $iterations ]; do
((i++))
done
end_time=$(date +%s%3N)
while_style_time=$((end_time - start_time))
echo "while 循环:${while_style_time}ms"
echo ""
echo "🏆 最快的方法: "
min_time=$c_style_time
fastest="C 风格 for 循环"
if [ $list_style_time -lt $min_time ]; then
min_time=$list_style_time
fastest="列表 for 循环"
fi
if [ $while_style_time -lt $min_time ]; then
min_time=$while_style_time
fastest="while 循环"
fi
echo "$fastest (${min_time}ms)"
}
benchmark_for_loops
#!/bin/bash
validate_input() {
local input="$1"
local pattern="$2"
local description="$3"
if [[ ! "$input" =~ $pattern ]]; then
echo "❌ 无效的 $description: '$input'" >&2
return 1
fi
return 0
}
# 安全的文件处理循环
safe_file_processing() {
local pattern="$1"
shift
for filename in "$@"
do
# 验证文件名不包含危险字符
if ! validate_input "$filename" '^[a-zA-Z0-9._-]+$' "文件名"; then
continue
fi
# 验证文件存在且是普通文件
if [ ! -f "$filename" ]; then
echo "⚠️ 文件不存在:$filename" >&2
continue
fi
# 验证文件可读
if [ ! -r "$filename" ]; then
echo "⚠️ 文件不可读:$filename" >&2
continue
fi
echo "✅ 安全处理:$filename"
# 实际处理逻辑...
done
}
# 使用示例
safe_file_processing "*.txt" "file1.txt" "file with spaces.txt" "dangerous;rm -rf /.txt"
#!/bin/bash
check_permissions() {
local required_permission="$1"
shift
for item in "$@"
do
case $required_permission in
"read")
if [ ! -r "$item" ]; then
echo "❌ 缺少读取权限:$item" >&2
return 1
fi
;;
"write")
if [ ! -w "$item" ]; then
echo "❌ 缺少写入权限:$item" >&2
return 1
fi
;;
"execute")
if [ ! -x "$item" ]; then
echo "❌ 缺少执行权限:$item" >&2
return 1
fi
;;
esac
done
return 0
}
# 安全的部署脚本
secure_deploy() {
local servers=("$@")
echo "🔒 安全检查..."
# 检查 SSH 密钥
if [ ! -f ~/.ssh/id_rsa ] && [ ! -f ~/.ssh/id_ed25519 ]; then
echo "❌ 未找到 SSH 私钥" >&2
return 1
fi
# 检查目标服务器可达性
for server in "${servers[@]}"
do
if ! ping -c 1 -W 2 "$server" >/dev/null 2>&1; then
echo "❌ 服务器不可达:$server" >&2
return 1
fi
done
echo "✅ 安全检查通过"
# 执行部署
for server in "${servers[@]}"
do
echo "🚀 部署到:$server"
# 实际部署逻辑...
done
}
# 使用示例
secure_deploy "server1.example.com" "server2.example.com"
随着 DevOps 和自动化运维的普及,Shell 脚本中的 for 循环也在不断演进。现代 Shell 脚本越来越多地与容器技术、云服务和 CI/CD 管道集成。
#!/bin/bash
# 批量管理 Docker 容器
manage_containers() {
action="$1"
shift
containers=("$@")
case $action in
"start")
for container in "${containers[@]}"
do
if docker inspect "$container" >/dev/null 2>&1; then
echo "▶️ 启动容器:$container"
docker start "$container"
else
echo "❌ 容器不存在:$container"
fi
done
;;
"stop")
for container in "${containers[@]}"
do
if docker ps -q --filter "name=$container" | grep -q .; then
echo "⏹️ 停止容器:$container"
docker stop "$container"
else
echo "⚠️ 容器未运行:$container"
fi
done
;;
"logs")
for container in "${containers[@]}"
do
echo "📋 容器日志:$container"
docker logs --tail 10 "$container"
echo "---"
done
;;
esac
}
# 使用示例
containers=("web-server" "database" "cache" "worker")
echo "🐳 Docker 容器管理"
manage_containers "logs" "${containers[@]}"
#!/bin/bash
# Kubernetes 资源管理脚本
kubectl_batch_operations() {
namespace="$1"
operation="$2"
shift 2
resources=("$@")
echo "☸️ Kubernetes $operation 操作 (命名空间:$namespace)"
for resource in "${resources[@]}"
do
case $operation in
"scale")
replicas="$resource"
deployments=$(kubectl get deployments -n "$namespace" -ojsonpath='{.items[*].metadata.name}')
for deployment in $deployments
do
echo "📏 扩展部署 $deployment 到 $replicas 个副本"
kubectl scale deployment "$deployment" --replicas="$replicas" -n "$namespace"
done
;;
"restart")
echo "🔄 重启部署:$resource"
kubectl rollout restart deployment "$resource" -n "$namespace"
;;
"status")
echo "📊 部署状态:$resource"
kubectl get deployment "$resource" -n "$namespace"
kubectl get pods -l app="$resource" -n "$namespace"
;;
esac
done
}
# 使用示例
kubectl_batch_operations "production" "status" "frontend" "backend" "database"
Shell 脚本中的 for 循环是一个强大而灵活的工具,它使我们能够自动化重复性任务、批量处理数据、管理系统资源。通过本文的详细介绍,我们了解了:
无论你是系统管理员、DevOps 工程师还是普通开发者,掌握 Shell 脚本中的 for 循环都将大大提升你的工作效率。记住,最好的学习方式是实践 - 从今天开始,尝试将你日常工作中的重复任务自动化吧!

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online
将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online