You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Shell脚本性能优化:如何加速每日处理15万文件的批量执行脚本

Shell脚本优化方案

原脚本核心问题

  • 语法错误:sed 命令行后多了一行无效的目标文件路径,执行会直接报错
  • 遍历文件/行用了 $(ls)、$(cat) 写法,不仅存在文件名/行内容包含特殊字符的兼容性问题,还会额外创建子进程
  • 每行处理都启动 awk、cut、grep、sed 四个独立子进程,百万级的进程调度开销是最大的性能瓶颈
  • 频繁执行小IO操作:逐行grep扫描目标文件、sed -i 重写整个目标文件,IO开销极高

优化方案

1. Shell原生语法优化(改动最小,性能提升3~5倍)

把所有外部命令替换成Shell内置操作,减少子进程创建,优化IO逻辑:

#!/bin/bash
shopt -s nullglob  # 匹配不到文件时glob返回空,避免报错
DATA_FILE_SOURCE="<path_to_source_data/${1}"
DATA_FILE_DEST="<path_to_dest>"

# 提前创建目标目录避免报错
mkdir -p "${DATA_FILE_DEST}" || exit 1

# 用glob遍历文件,不要解析ls
for fname in "${DATA_FILE_SOURCE}"/*; do
    # 跳过非文件项
    [[ -f "${fname}" ]] || continue
    # 用内置read逐行读文件,不要用cat
    while IFS=, read -r col1 col2 content || [[ -n "${content}" ]]; do
        target_file="${DATA_FILE_DEST}/${col1}.${col2}.daily.csv"
        if [[ ! -f "${target_file}" ]]; then
            echo "${content}" > "${target_file}"
        else
            if ! grep -Fxq "${content}" "${target_file}"; then
                # 保留原脚本删除含${1}行的逻辑,确认符合业务需求再使用
                sed -i "/${1}/d" "${target_file}"
                echo "${content}" >> "${target_file}"
            fi
        fi
    done < "${fname}"
done

2. 全量awk实现(性能提升10~20倍,推荐)

awk是文本处理专用工具,单进程即可完成所有分割、去重、写文件操作,完全避免频繁子进程和碎片化IO:

#!/usr/bin/awk -f
BEGIN {
    # 传入参数说明:ARGV[1]为脚本第一个参数$1,ARGV[2]为目标路径
    src_prefix = ARGV[1]
    dest_path = ARGV[2]
    ARGV[1] = ""
    ARGV[2] = ""
    FS = ","
}

# 逐行处理所有输入文件
{
    target_file = dest_path "/" $1 "." $2 ".daily.csv"
    content = substr($0, length($1) + length($2) + 3)
    # 内存去重:同个目标文件的重复内容自动覆盖
    file_content[target_file, content] = 1
}

END {
    # 所有行处理完成后,一次性批量写入所有目标文件
    for (key in file_content) {
        split(key, arr, SUBSEP)
        f = arr[1]
        c = arr[2]
        # 首次写该文件时先处理原有内容
        if (!(f in written)) {
            written[f] = 1
            # 原文件存在的话先过滤掉含src_prefix的行
            if (system("test -f " f) == 0) {
                while ((getline line < f) > 0) {
                    if (line !~ src_prefix) {
                        print line > f
                    }
                }
                close(f)
            }
        }
        # 写入去重后的新内容
        print c >> f
        close(f)
    }
}

调用方式:

chmod +x process.awk
./process.awk "${1}" "<path_to_dest>" <path_to_source_data/${1}>/*

额外优化建议

  • 如果目标文件不需要保留历史内容,直接覆盖写入即可,省去读旧文件的开销
  • 目标文件内容较多的场景,可以用 sort -u 批量去重,比逐行grep效率高很多
  • 存在磁盘IO瓶颈的话,可以把目标目录放到tmpfs内存文件系统处理,完成后再同步到磁盘

内容的提问来源于stack exchange,提问作者usert4jju7

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 22:39:05