使用CDO与Shell脚本将小时级NetCDF文件合并为日级文件:构造合并命令的实现方法
First off, let's fix a common pitfall with your initial variable setup: storing ls output in a regular variable can cause issues if your filenames contain spaces or special characters. Instead, use a shell array to safely hold all your NetCDF files—this is way more reliable:
# Use a shell array to store all .nc files (sorted alphabetically by default) files=(*.nc)
Now, to merge every 24 hourly files into a single daily file, we can use a for loop with a step size of 24. Here's a complete, robust implementation:
# Check if we have any files to process if [ ${#files[@]} -eq 0 ]; then echo "No .nc files found in the current directory!" exit 1 fi # Loop through the array in batches of 24 for ((i=0; i<${#files[@]}; i+=24)); do # Calculate the end index of the current batch (avoid exceeding array length) end=$((i+23)) if [ $end -ge ${#files[@]} ]; then end=$((${#files[@]}-1)) echo "Warning: Final batch has fewer than 24 files (from index $i to $end)" fi # Extract the current batch of files batch_files=("${files[@]:i:24}") # Define a clean, sorted output filename (customize this to your needs) # Example: day_01.nc, day_02.nc, etc. output_file="day_$(printf "%02d" $((i/24 +1))).nc" # Construct and run the CDO merge command echo "Merging files ${batch_files[*]} into $output_file..." cdo merge "${batch_files[@]}" "$output_file" done
Let's break this down:
- Array Setup:
files=(*.nc)creates an array where each element is a separate filename, completely avoiding issues with spaces or special characters in filenames. - Batch Loop: The
for ((i=0; i<${#files[@]}; i+=24))loop increments by 24 each iteration, so we process one full day's worth of hourly files per run. - Edge Case Handling: The code checks if the final batch has fewer than 24 files and warns you, instead of failing silently.
- Output Naming: Using
printf "%02d"ensures day numbers are zero-padded (e.g.,01instead of1) for consistent filesystem sorting. - CDO Command:
"${batch_files[@]}"expands to each filename as a separate argument—exactly what CDO expects for itsmergeoperation.
If you really want to stick with your original variable (not recommended):
If you insist on using files=$(ls *.nc) (note: this is not ideal for filenames with spaces), you can convert it to an array first:
files_str=$(ls *.nc) read -ra files <<< "$files_str" # Then use the same loop as above
Just remember: using ls in scripts is generally discouraged because it can break with non-standard filenames. The array approach with *.nc is the safer, more robust choice.
内容的提问来源于stack exchange,提问作者João Janeiro

