Skip to content

批量处理脚本

本节介绍常用的批量文件处理脚本,包括批量重命名、格式转换、数据处理和并行任务执行。

批量重命名

bash
#!/usr/bin/env bash
#
# 批量重命名脚本
# 用法:./rename.sh <目录> <原模式> <新模式>
#

set -euo pipefail

DIR="${1:-.}"
OLD_PATTERN="${2:?请提供原模式}"
NEW_PATTERN="${3:?请提供新模式}"

echo "目录:$DIR"
echo "替换:$OLD_PATTERN$NEW_PATTERN"
echo ""

count=0
while IFS= read -r -d '' file; do
    dir=$(dirname "$file")
    base=$(basename "$file")
    new_base="${base/$OLD_PATTERN/$NEW_PATTERN}"

    if [[ "$base" != "$new_base" ]]; then
        new_file="$dir/$new_base"
        echo "  $file$new_file"
        mv "$file" "$new_file"
        (( count++ ))
    fi
done < <(find "$DIR" -maxdepth 1 -type f -print0)

echo ""
echo "共重命名 $count 个文件"
bash
# 使用示例
./rename.sh ./photos ".JPG" ".jpg"          # 扩展名统一小写
./rename.sh ./docs "report_" "2025_report_" # 添加前缀
./rename.sh . " " "_"                       # 空格替换为下划线

批量图片处理

bash
#!/usr/bin/env bash
#
# 批量图片压缩和转换(需要 ImageMagick)
#

set -euo pipefail

INPUT_DIR="${1:?请提供输入目录}"
OUTPUT_DIR="${2:-${INPUT_DIR}/compressed}"
QUALITY="${3:-80}"
MAX_WIDTH="${4:-1920}"

command -v convert >/dev/null 2>&1 || { echo "需要安装 ImageMagick"; exit 1; }
mkdir -p "$OUTPUT_DIR"

processed=0
failed=0

while IFS= read -r -d '' img; do
    filename=$(basename "$img")
    output="${OUTPUT_DIR}/${filename%.*}.jpg"

    echo "处理:$img"
    if convert "$img" \
        -resize "${MAX_WIDTH}x${MAX_WIDTH}>" \
        -quality "$QUALITY" \
        -strip \
        "$output" 2>/dev/null; then
        orig_size=$(stat -c %s "$img")
        new_size=$(stat -c %s "$output")
        ratio=$(( (orig_size - new_size) * 100 / orig_size ))
        echo "  → $output(压缩率:${ratio}%)"
        (( processed++ ))
    else
        echo "  ❌ 失败:$img"
        (( failed++ ))
    fi
done < <(find "$INPUT_DIR" -maxdepth 1 \( -name "*.jpg" -o -name "*.png" -o -name "*.jpeg" \) -print0)

echo ""
echo "完成:处理 $processed 张,失败 $failed 张"

批量文本处理

bash
#!/usr/bin/env bash
#
# 批量替换文件中的文本内容
#

set -euo pipefail

DIR="${1:-.}"
OLD_TEXT="${2:?请提供要替换的文本}"
NEW_TEXT="${3:?请提供替换后的文本}"
FILE_PATTERN="${4:-*.txt}"

echo "目录:$DIR"
echo "替换:$OLD_TEXT$NEW_TEXT"
echo "文件模式:$FILE_PATTERN"
echo ""

count=0
while IFS= read -r -d '' file; do
    if grep -q "$OLD_TEXT" "$file" 2>/dev/null; then
        # 创建备份
        cp "$file" "${file}.bak"
        # 执行替换
        sed -i "s|${OLD_TEXT}|${NEW_TEXT}|g" "$file"
        echo "  已修改:$file"
        (( count++ ))
    fi
done < <(find "$DIR" -name "$FILE_PATTERN" -type f -print0)

echo ""
echo "共修改 $count 个文件(原文件已备份为 .bak)"

并行批量处理

bash
#!/usr/bin/env bash
#
# 并行任务处理器
# 控制并发数量,避免系统过载
#

set -euo pipefail

MAX_JOBS=4       # 最大并发数
TASK_FILE="${1:?请提供任务文件(每行一个任务)}"

# 等待任务槽位
wait_for_slot() {
    while (( $(jobs -r | wc -l) >= MAX_JOBS )); do
        sleep 0.5
    done
}

# 处理单个任务的函数(根据实际需求修改)
process_task() {
    local task="$1"
    echo "处理:$task"
    # 在此添加实际处理逻辑
    sleep 1   # 模拟耗时操作
    echo "完成:$task"
}

total=$(wc -l < "$TASK_FILE")
done_count=0

echo "总任务数:$total,并发数:$MAX_JOBS"
echo ""

while IFS= read -r task; do
    [[ -z "$task" || "$task" == \#* ]] && continue   # 跳过空行和注释

    wait_for_slot
    process_task "$task" &
    (( done_count++ ))
    echo "进度:${done_count}/${total}"
done < "$TASK_FILE"

# 等待所有后台任务完成
wait
echo ""
echo "所有任务处理完成!"

CSV 数据批量处理

bash
#!/usr/bin/env bash
#
# 批量处理 CSV 文件
# 示例:过滤、汇总、格式转换
#

set -euo pipefail

INPUT_CSV="${1:?请提供 CSV 文件}"
OUTPUT_CSV="${2:-output.csv}"

# 去掉重复行(保留表头)
deduplicate_csv() {
    local input="$1"
    local output="$2"
    head -1 "$input" > "$output"
    tail -n +2 "$input" | sort | uniq >> "$output"
    echo "去重完成:$output"
}

# 统计每列数据
summarize_csv() {
    local input="$1"
    local col="${2:-1}"   # 默认统计第 1 列

    echo "=== 第 ${col} 列统计 ==="
    awk -F, -v col="$col" 'NR>1 {print $col}' "$input" | \
        sort | uniq -c | sort -rn | head 20
}

# 过滤包含关键词的行
filter_csv() {
    local input="$1"
    local keyword="$2"
    local output="$3"

    head -1 "$input" > "$output"
    grep -i "$keyword" "$input" | grep -v "^$(head -1 "$input")" >> "$output"
    echo "过滤完成:$(wc -l < "$output") 行 → $output"
}

# 合并多个 CSV 文件(相同格式)
merge_csv() {
    local output="$1"
    shift
    local files=("$@")

    head -1 "${files[0]}" > "$output"
    for f in "${files[@]}"; do
        tail -n +2 "$f" >> "$output"
    done
    echo "合并完成:${#files[@]} 个文件 → $output($(wc -l < "$output") 行)"
}

# 示例调用
deduplicate_csv "$INPUT_CSV" "dedup_${OUTPUT_CSV}"
summarize_csv "$INPUT_CSV" 2
filter_csv "$INPUT_CSV" "active" "filtered_${OUTPUT_CSV}"

批量下载

bash
#!/usr/bin/env bash
#
# 从 URL 列表批量下载文件
#

set -euo pipefail

URL_FILE="${1:?请提供 URL 列表文件}"
OUTPUT_DIR="${2:-./downloads}"
MAX_PARALLEL=3

mkdir -p "$OUTPUT_DIR"

download_file() {
    local url="$1"
    local filename
    filename=$(basename "$url" | cut -d? -f1)
    local output="${OUTPUT_DIR}/${filename}"

    if [[ -f "$output" ]]; then
        echo "已存在,跳过:$filename"
        return 0
    fi

    echo "下载:$url"
    if curl -fsSL -o "$output" "$url"; then
        echo "完成:$filename($(du -h "$output" | cut -f1))"
    else
        echo "失败:$url" >&2
        rm -f "$output"
    fi
}

export -f download_file
export OUTPUT_DIR

# 使用 xargs 并行下载
cat "$URL_FILE" | grep -v '^#' | grep -v '^$' | \
    xargs -P "$MAX_PARALLEL" -I {} bash -c 'download_file "{}"'

echo "下载完成!文件保存在:$OUTPUT_DIR"

使用方法

bash
# 批量重命名
chmod +x rename.sh
./rename.sh ./photos ".JPEG" ".jpg"

# 并行处理任务(任务文件每行一个)
cat > tasks.txt << 'EOF'
task1
task2
task3
EOF
./parallel_process.sh tasks.txt

# 批量下载
cat > urls.txt << 'EOF'
https://example.com/file1.zip
https://example.com/file2.zip
EOF
./batch_download.sh urls.txt ./downloads