当前位置: 首页 > news >正文

高效处理NetCDF文件经纬度转换:一个纯CDO驱动的Bash脚本详解

前言

在气候科学、海洋学和地球系统建模领域,NetCDF(Network Common Data Form)文件是存储多维科学数据的标准格式。然而,这些文件常常面临经纬度范围不一致的问题——有些数据使用[-180, 180]的地理标准范围,而另一些则采用[0, 360]的气象标准,甚至偶尔出现跨越日期变更线或特殊范围(如20.5-379.5)的异常。这不仅会干扰数据可视化和分析,还可能导致模型输入错误。作为一名从事地理信息系统和数据处理的从业者,我经常遇到这类挑战,因此开发了一个灵活的Bash脚本,利用强大的CDO(Climate Data Operators)工具来自动化处理这些问题。

这个脚本支持单文件和批量模式,能够轻松实现经度范围转换、纬度顺序反转,并自动检测特殊情况,如跨越日期变更线的数据。它还集成了并行处理、日志记录和进度显示等实用功能,帮助用户高效管理大规模数据集。在这篇博客中,我将详细介绍脚本的配置、使用方法、核心代码逻辑,以及一些实际应用案例和优化建议。无论你是科研工作者、数据分析师,还是初学者,这款脚本都能显著简化你的工作流程。让我们一起来探索如何让NetCDF数据处理变得更智能、更可靠!

脚本

#!/bin/bash# ================================================================
#                    NC文件经纬度转换脚本
#                      纯CDO版本 v3.0
# ================================================================
# 功能说明:
#   1. 支持单文件和批量处理模式
#   2. 支持经度范围转换, -180-180和0-360之间转换(包括20.5-379.5等特殊范围)
#   3. 支持纬度反转
#   4. 自动检测并处理跨越日期变更线的数据
# ================================================================# ┌──────────────────────────────────────────────────────────────┐
# │                         参数配置区                            │
# │              请根据需求修改以下参数,然后运行脚本              │
# └──────────────────────────────────────────────────────────────┘# ══════════════════════════════════════════════════════════════════════
# 1. 基本路径和模式配置
# ══════════════════════════════════════════════════════════════════════# INPUT_PATH - 输入路径(必填)| 单文件路径 | 目录路径
# 说明:要处理的NC文件路径或包含NC文件的目录路径
INPUT_PATH="test" # 替换成自己的路径# OUTPUT_PATH - 输出路径(选填)| 留空自动生成 | 指定文件/目录路径  
# 说明:留空时单文件模式生成"原名_xxx.nc",批量模式创建"输入目录_processed"
OUTPUT_PATH="test_processed" #替换成自己的路径# PROCESS_MODE - 处理模式 | auto(自动检测) | single(单文件) | batch(批量)
# 说明:auto根据INPUT_PATH自动判断,推荐使用
PROCESS_MODE="auto"# ══════════════════════════════════════════════════════════════════════
# 2. 经纬度处理配置
# ══════════════════════════════════════════════════════════════════════# PROCESS_LONGITUDE - 经度处理 | yes(启用) | no(禁用)
# 说明:是否对经度进行范围转换,处理跨日期变更线等问题
PROCESS_LONGITUDE="yes"# LONGITUDE_TARGET - 目标范围 | [-180,180](地理标准) | [0,360](气象标准)
# 说明:[-180,180]西经为负值,[0,360]所有经度为正值,会自动处理>360度的特殊范围
LONGITUDE_TARGET="[0,360]" #"[-180,180]"# LONGITUDE_METHOD - 处理方法 | auto(自动) | sellonlatbox | shiftlon | expr  
# 说明:auto自动选择最佳方法,expr适合特殊范围(如20.5-379.5)
LONGITUDE_METHOD="auto"# SPECIAL_LON_HANDLING - 特殊经度处理(>360度) | yes(启用) | no(禁用)
# 说明:自动检测并处理超过360度的经度范围
SPECIAL_LON_HANDLING="yes"# PROCESS_LATITUDE - 纬度处理(反转顺序) | yes(启用) | no(禁用) 
# 说明:反转纬度顺序(北→南 ↔ 南→北),用于某些模型输出格式转换
PROCESS_LATITUDE="yes"# ══════════════════════════════════════════════════════════════════════
# 3. 文件处理选项  
# ══════════════════════════════════════════════════════════════════════# FILE_SUFFIX - 输出文件后缀 | 任意字符串
# 说明:自定义后缀,会自动添加处理类型标识(如_lon-180-180)
FILE_SUFFIX="processed"# OVERWRITE_EXISTING - 覆盖已存在文件 | yes(覆盖) | no(跳过) | backup(备份后覆盖)
# 说明:backup会创建.bak备份文件
OVERWRITE_EXISTING="no"# SKIP_PATTERN - 跳过文件模式 | 留空不跳过 | *test* | *_processed* 等通配符
# 说明:批量处理时跳过匹配此模式的文件,支持*?[]通配符
SKIP_PATTERN="*_processed*"# CHECK_OUTPUT - 检查输出文件完整性 | yes(检查) | no(不检查)
# 说明:处理后验证输出文件是否正确生成且可读
CHECK_OUTPUT="yes"# KEEP_TEMP_FILES - 保留临时文件(调试用) | yes(保留) | no(删除)
# 说明:调试时可保留中间文件,正常使用建议删除
KEEP_TEMP_FILES="no"# ══════════════════════════════════════════════════════════════════════
# 4. 性能和日志配置
# ══════════════════════════════════════════════════════════════════════# PARALLEL_PROCESSING - 并行处理(需GNU parallel) | yes(启用) | no(串行)
# 说明:批量模式下同时处理多个文件,需要先安装parallel工具
PARALLEL_PROCESSING="yes"# MAX_PARALLEL_JOBS - 最大并行数 | auto(自动) | 4 | 8 | 16 等正整数
# 说明:建议设为CPU核心数的50-75%,auto根据CPU自动决定, 但是使用auto的时候会报错。
MAX_PARALLEL_JOBS="4"# CDO_OPTIONS - CDO选项 | -s(静默) | -v(详细) | -O(覆盖) | -z zip_9(压缩)
# 说明:可组合使用,如"-s -z zip_6"表示静默+压缩
CDO_OPTIONS="-v"# LOG_LEVEL - 日志级别 | ERROR | WARN | INFO(推荐) | DEBUG
# 说明:INFO显示主要处理信息,DEBUG显示详细调试信息
LOG_LEVEL="INFO"# LOG_FILE - 日志文件 | auto(自动生成) | 指定路径 | 留空禁用
# 说明:auto生成带时间戳的日志文件,留空则不保存日志
LOG_FILE="auto"# SHOW_PROGRESS - 显示进度 | yes(显示) | no(不显示)
# 说明:批量处理时显示进度条和百分比
SHOW_PROGRESS="yes"# DRY_RUN - 演练模式(仅显示操作) | yes(演练) | no(正常执行)
# 说明:演练模式只显示将要执行的操作,不实际处理文件
DRY_RUN="no"# ┌──────────────────────────────────────────────────────────────┐
# │                    参数配置结束                              │
# │                  以下为脚本执行代码                          │
# │                    请勿修改!                                │
# └──────────────────────────────────────────────────────────────┘# ================================================================
#                         脚本执行部分
# ================================================================# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
MAGENTA='\033[0;35m'
NC='\033[0m'# 全局变量
SCRIPT_NAME=$(basename "$0")
SCRIPT_DIR=$(dirname "$(readlink -f "$0")")
START_TIME=$(date +%s)
PROCESSED_COUNT=0
FAILED_COUNT=0
SKIPPED_COUNT=0# 生成日志文件名
if [ "$LOG_FILE" = "auto" ]; then# 尝试在当前目录创建日志文件,如果失败则使用临时目录LOG_FILE="nc_process_$(date +%Y%m%d_%H%M%S).log"if ! touch "$LOG_FILE" 2>/dev/null; thenLOG_FILE="/tmp/nc_process_$(date +%Y%m%d_%H%M%S).log"if ! touch "$LOG_FILE" 2>/dev/null; thenLOG_FILE="/dev/null"echo "警告: 无法创建日志文件,日志将被禁用"fifi
elif [ -z "$LOG_FILE" ]; thenLOG_FILE="/dev/null"
fi# ========================
# 日志函数
# ========================
log() {local level=$1shiftlocal message="$*"local timestamp=$(date '+%Y-%m-%d %H:%M:%S')case $level inERROR)[ "$LOG_LEVEL" != "NONE" ] && echo -e "${RED}[ERROR]${NC} $message" >&2[ "$LOG_FILE" != "/dev/null" ] && echo "[$timestamp] [ERROR] $message" >> "$LOG_FILE" 2>/dev/null;;WARN)if [[ "$LOG_LEVEL" =~ ^(WARN|INFO|DEBUG)$ ]]; thenecho -e "${YELLOW}[WARN]${NC} $message"fi[ "$LOG_FILE" != "/dev/null" ] && echo "[$timestamp] [WARN] $message" >> "$LOG_FILE" 2>/dev/null;;INFO)if [[ "$LOG_LEVEL" =~ ^(INFO|DEBUG)$ ]]; thenecho -e "${GREEN}[INFO]${NC} $message"fi[ "$LOG_FILE" != "/dev/null" ] && echo "[$timestamp] [INFO] $message" >> "$LOG_FILE" 2>/dev/null;;DEBUG)if [ "$LOG_LEVEL" = "DEBUG" ]; thenecho -e "${CYAN}[DEBUG]${NC} $message"fi[ "$LOG_FILE" != "/dev/null" ] && echo "[$timestamp] [DEBUG] $message" >> "$LOG_FILE" 2>/dev/null;;*)echo "$message"[ "$LOG_FILE" != "/dev/null" ] && echo "[$timestamp] $message" >> 
http://www.dtcms.com/a/342587.html

相关文章:

  • GitHub 热榜项目 - 日榜(2025-08-21)
  • 009.Redis Predixy + Sentinel 架构
  • 深度卷积神经网络AlexNet
  • 【NVIDIA-B200】生产报错 Test CUDA failure common.cu:1035 ‘system not yet initialized‘
  • Docker 搭建 Gitlab 实现自动部署Vue项目
  • NW755NW776美光固态闪存NW863NX595
  • 【永洪BI】报告脚本-JavaScript使用【完整版】
  • Vue 项目中父子传值使用Vuex异步数据不更新问题
  • Postman来做API安全测试:身份验证缺陷漏洞测试
  • 药品追溯码(溯源码)采集系统(二):门诊发药后端
  • 【Linux系统】进程信号:信号的产生和保存
  • 使用EasyExcel 导出复杂的合并单元格
  • 第四届中国高校机器人实验教学创新大赛团队参赛总结
  • selenium一些进阶方法如何使用
  • 大模型0基础开发入门与实践:第11章 进阶:LangChain与外部工具调用
  • 打破传统课程模式,IP变现的创新玩法 | 创客匠人
  • 从零开始学 Selenium:浏览器驱动、元素定位与实战技巧
  • 微服务:现代软件架构的主流范式
  • Linux mmap内存映射
  • 集中式负载均衡 vs. 分布式负载均衡
  • 【赵渝强老师】Redis Cluster分布式集群
  • #千问海报大赛
  • 订单簿动力学与深度学习模型的融合大单识别与短期市场价格波动预测
  • Java多线程编程基础篇
  • 多级缓存一致性矩阵:ABP vNext 下的旁路 / 写穿 / 写回组合实战
  • Qt的moveToThread使用
  • SQL-leetcode—3451. 查找无效的 IP 地址
  • centos常用命令
  • Visual Studio Code (VS Code) 工作区配置文件的作用
  • CentOS7安装部署NexusRepository