使用Bash脚本合并Google Cloud Storage中多份CSV文件并保留单份表头
修正GCS多CSV文件合并的Bash脚本问题
问题根源
原脚本的核心问题在于循环逻辑错误:每次合并时始终使用初始的第一个文件内容与当前文件的内容拼接,而非基于上一次合并后的结果继续追加。这就导致每次循环都会覆盖之前的合并内容,最终仅保留第一个文件和最后一个文件的内容。此外,循环内频繁上传文件也会降低效率。
修正后的脚本
#!/bin/bash # 校验参数是否完整 if [ $# -lt 3 ]; then echo "Usage: $0 <bucket_name> <starting_text> <target_file_name>" exit 1 fi BUCKET_NAME="$1" STARTING_TEXT="$2" TARGET_FILE_NAME="$3" TIMESTAMP=$(date +"%Y%m%d%H%M%S") MERGED_TMP="/tmp/merged_file.csv" # 获取目标CSV文件列表 FILES=($(gsutil ls gs://$BUCKET_NAME/$STARTING_TEXT*.csv)) # 校验是否存在目标文件 if [ ${#FILES[@]} -eq 0 ]; then echo "No CSV files found matching pattern: gs://$BUCKET_NAME/$STARTING_TEXT*.csv" exit 1 elif [ ${#FILES[@]} -eq 1 ]; then echo "Only one file found, copying directly as merged file" gsutil cp "${FILES[0]}" "gs://$BUCKET_NAME/${TARGET_FILE_NAME}_${TIMESTAMP}.csv" exit 0 fi # 初始化合并文件:写入第一个文件的完整内容(含表头) gsutil cat "${FILES[0]}" > "$MERGED_TMP" # 打印待合并文件列表 echo "Merging the following files:" for FILE in "${FILES[@]}" do echo "$FILE" done # 循环处理剩余文件:跳过表头,追加内容 for ((i=1; i<${#FILES[@]}; i++)) do # 直接读取远程文件并跳过表头,追加到合并文件 gsutil cat "${FILES[i]}" | tail -n +2 >> "$MERGED_TMP" done # 合并完成后一次性上传到GCS gsutil cp "$MERGED_TMP" "gs://$BUCKET_NAME/${TARGET_FILE_NAME}_${TIMESTAMP}.csv" # 清理临时文件 rm "$MERGED_TMP" echo "Merge completed successfully: gs://$BUCKET_NAME/${TARGET_FILE_NAME}_${TIMESTAMP}.csv"
关键修改点
- 修复循环逻辑:不再每次重新拼接初始文件,而是直接将后续文件的内容(跳过表头)追加到合并文件中,保证所有文件内容都被累计
- 优化GCS交互:仅在合并完成后上传一次文件,减少网络请求次数,提升效率
- 增加边界处理:处理文件数量为0或1的情况,避免无意义的循环
- 简化临时文件:只使用一个临时文件,减少磁盘IO和文件管理复杂度
- 完善参数校验:确保用户传入所有必要参数,避免因参数缺失导致的错误
内容的提问来源于stack exchange,提问作者Saurabh
相关产品推荐
相关产品推荐

