【问题标题】:Bash script loop through netCDF files via placeholder and use cdo commandsBash 脚本通过占位符循环遍历 netCDF 文件并使用 cdo 命令
【发布时间】:2017-12-06 02:55:21
【问题描述】:

我想循环浏览 40 个 netCDF 文件。有 20 个带有变量 PRECC 的文件和 20 个带有变量 PRECL("modelmember001.PRECC.192001-200512.nc", "modelmember002.PRECC.192001-200512.nc", ... ,"modelmember020.PRECC.192001-200512.nc" 和 PRECL 的文件)。

我需要使用循环执行多个 cdo(气候数据运算符)命令(添加 PRECC 和 PRECL 文件,并将时间序列从 1920-2005 更改为 1955-2005)。

这是我使用的代码:

  datadir="path_to_mydatat"
    workdir="path_to_folder_for_newfiles"
    members="{001 .. 020}"

    for model in $members
    do

    echo 'working with model' ${model}

    echo cdo -s add ${datadir}/modelmember${members}.PRECC.192001-200512.nc${datadir}/modelmember${members}.PRECL.192001-200512.nc ${workdir}/modelmember${members}PRECT.192001-200512.nc
    # echo cdo -s selyear,1955/2005 ${workdir}/modelmember${members}.PRECT.192001-200512.nc ${workdir}/modelmember${members}.PRECT.195501-200512.nc

最终我需要 20 个名称为

的文件
"modelmember001.PRECT.195501-200512.nc", "modelmember002.PRECT.195501-200512.nc", ... , "modelmember020.PRECT.195501-200512.nc"

这是我在运行代码时得到的结果(故意在 cdo 行前面加上“echo”):

$./cdo_add.sh

{001 .. 020}

working with model {001

cdo -s add /path_to_mydatat/modelmember{001 .. 020}.PRECC.192001-200512.nc         /path_to_mydatat/modelmember{001 .. 020}.PRECL.192001-200512.nc  /path_to_folder_for_newfiles/modelmember{001 .. 020}.PRECT.192001-200512.nc

working with model ..

cdo -s add /path_to_mydatat/modelmember{001 .. 020}.PRECC.192001-200512.nc /path_to_mydatat/modelmember{001 .. 020}.PRECL.192001-200512.nc /path_to_folder_for_newfiles/modelmember{001 .. 020}.PRECT.192001-200512.nc

working with model 020}

cdo -s add /path_to_mydatat/modelmember{001 .. 020}.PRECC.192001-200512.nc /path_to_mydatat/modelmember{001 .. 020}.PRECL.192001-200512.nc /path_to_folder_for_newfiles/modelmember{001 .. 020}.PRECT.192001-200512.nc

我的代码似乎没有遍历成员。我使用占位符“成员”的方式有问题,但我不知道如何解决它。 有人有建议吗? 干杯!

【问题讨论】:

  • for model in {001..020} -- 你可以使用变量。摆脱members="{001 .. 020}"(它会导致循环001然后..然后020)
  • 这里有一个类似的问题和解决方案:stackoverflow.com/q/169511/754550

标签: bash for-loop netcdf cdo-climate


【解决方案1】:

您的代码似乎没有循环,因为您不能将大括号扩展分配给变量并期望它在for 循环中替换时会扩展。下面将文字字符串"{001 .. 020}"保存到变量members中,例如

members="{001 .. 020}"

当您在for model in $members 中使用members 时,会发生正常的分词,因为它只是一个字符串,并且您使用001 循环一次,然后使用..,最后使用020——这不是预期的来自001, 002, 003, ... 020 的序列。 (数字和.. 之间不应有空格开头——但这仍然不允许您在变量中使用扩展)

要正确使用扩展,请完全摆脱 members 变量并在循环中使用 {001..020},例如

for model in {001..020}   ## (notice NO space between 001 and ..)

示例:

$ for m in {001..020}; do echo $m; done
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020

这将允许您循环使用model 中的序列。

根据 cmets 中的对话,我知道您有 40 个文件,前缀为 modelmemberXXX(其中 XXX 是 001-020),后跟 .PRECC* 或 .PRECL*(每个文件 20 个文件)协调将匹配对馈送到 cdo 命令。虽然首选的方法是循环一个匹配的 glob,例如for i in modelmember*.PRECC*; do,你也可以使用大括号展开方式,例如

for i in {001..020}
do 
    a=$(echo modelmember${i}.PRECC*)
    b=$(echo modelmember${i}.PRECL*)
    if [ -e "$a" ] && [ -f "$b" ]
    then
        printf "%s\n%s\n\n" "$a" "$b"
    fi
done

(注意[ -e "$a" ] && [ -f "$b" ] 测试只是确保在继续执行命令之前对中的两个文件都存在(printf 此处))

示例输出

modelmember001.PRECC.192001-200512.nc
modelmember001.PRECL.192001-200512.nc

modelmember002.PRECC.192001-200512.nc
modelmember002.PRECL.192001-200512.nc

modelmember003.PRECC.192001-200512.nc
modelmember003.PRECL.192001-200512.nc
...
modelmember020.PRECC.192001-200512.nc
modelmember020.PRECL.192001-200512.nc

您只需在循环中使用$a 和$b 以及您需要的任何cdo_cmd。 (如 cmets 中所述,您需要切换到包含文件的目录,或在文件名前加上 path/to/the/files)

首选方式

而不是使用大括号扩展,可能更喜欢循环一组(PRECC 或PRECL),验证另一个存在,然后执行命令,例如

for i in modelmember*.PRECC* 
do
    b="${i/PRECC/PRECL}"
    if [ -e "$i" ] && [ -f "$b" ]
    then
        printf "%s\n%s\n\n" "$i" "$b"
    fi
done

(相同的输出)

【讨论】:

  • 感谢您的建议!这解决了循环的问题。如果我摆脱变量“成员”,我如何告诉循环成对执行 cdo 函数(例如modelmember001PRECC.192001-200512.nc 和modelmember001PRECL.192001-200512.nc?
  • 变量PRECL 真的包含逗号分隔值吗?例如PRECL("modelmember001.PRECC.192001-200512.nc", "modelmember002.PRECC.192001-200512.nc",...??如果是我,我会将一个变量读入一个数组(例如IFS=$', \t\n'; arrayCL=(echo $PRECL),然后循环遍历该数组for i in ${arrayCL[@]}; do somecdocmd "$i" ${i/PRECC/PRECL}"; done 中的每个文件,其中使用子字符串替换的参数扩展 将PRECC 更改为@ 987654361@给你对应的配对文件。(你可以添加一个test -e ${i/PRECC/PRECL}"来确保配对文件存在。)
  • 如果PRECL(...) 已经是一个数组,那么只需遍历每个数组中的索引(假设它们具有相同数量的元素)for ((i = 0; i < ${#PRECL[@]}; i++)); do somecdocmd "${PRECL[I]}" "${PRECC[I]}"; done。您可以测试元素是否与上一条注释中的参数扩展成对。
  • 编辑——在第一条评论中应该是arrayCL=($(echo $PRECL))——我忘记了命令替换。您也可以在 bash $(<<<$PRECL) 中使用 herestring。 (您也可以使用类似的扩展来解决重命名为CT 的问题,例如${i/PRECC/PRECT} 将CC 替换为CT(或将CL 替换为CT))
  • Grrr 这就是为什么不使用全大写作为变量名的原因。在第二条评论中应该是do somecdocmd "${PRECL[i]}" "${PRECC[i]}"——大写锁定仍在:(
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-01-16
  • 1970-01-01
  • 1970-01-01
  • 2019-01-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多