shell 在bash脚本中将索引增加1

ep6jt1vc  于 12个月前  发布在  Shell
关注(0)|答案(3)|浏览(140)

我有一个相当简单的shell脚本,它有一个相当基本的问题。我有多个文件遵循此约定:

TOTAL_summer_2003-06-01.nc
TOTAL_summer_2003-06-02.nc
TOTAL_summer_2003-06-03.nc
TOTAL_summer_2003-06-04.nc
TOTAL_summer_2003-07-01.nc
TOTAL_summer_2003-07-02.nc
TOTAL_summer_2003-07-03.nc
TOTAL_summer_2003-07-04.nc
TOTAL_summer_2003-08-01.nc
TOTAL_summer_2003-08-02.nc
TOTAL_summer_2003-08-03.nc
TOTAL_summer_2003-08-04.nc

希望结构清晰,有月有日的增加。现在我想用cdo从第二天减去前一天。如果我把它放在单行中,它看起来像这样:

cdo sub TOTAL_summer_2003-06-02.nc TOTAL_summer_2003-06-01.nc RAIN_summer_2003-06-01.nc
cdo sub TOTAL_summer_2003-06-03.nc TOTAL_summer_2003-06-02.nc RAIN_summer_2003-06-02.nc
cdo sub TOTAL_summer_2003-06-04.nc TOTAL_summer_2003-06-03.nc RAIN_summer_2003-06-03.nc

我想模式很明显了。当然,这可以通过使用一个循环来完成,我这样尝试:

for i in `seq 6 8`
    do
    for j in 0{1,2,3,4}     
        do
        cdo sub TOTAL_summer_2003-0${i}-${j+1}.nc TOTAL_summer_2003-0${i}-${j}.nc RAIN_summer_2003-0${i}-${j}.nc
    done
done

但这不起作用,因为${j+1}不做我想做的。我需要它比实际的j值高一个。
如果将echo命令而不是cdo sub添加到脚本中,则返回以下内容:

TOTAL_summer_2003-06-1.nc TOTAL_summer_2003-06-01.nc RAIN_summer_2003-06-01.nc
TOTAL_summer_2003-06-1.nc TOTAL_summer_2003-06-02.nc RAIN_summer_2003-06-02.nc
TOTAL_summer_2003-06-1.nc TOTAL_summer_2003-06-03.nc RAIN_summer_2003-06-03.nc
TOTAL_summer_2003-06-1.nc TOTAL_summer_2003-06-04.nc RAIN_summer_2003-06-04.nc
TOTAL_summer_2003-07-1.nc TOTAL_summer_2003-07-01.nc RAIN_summer_2003-07-01.nc
TOTAL_summer_2003-07-1.nc TOTAL_summer_2003-07-02.nc RAIN_summer_2003-07-02.nc
TOTAL_summer_2003-07-1.nc TOTAL_summer_2003-07-03.nc RAIN_summer_2003-07-03.nc
TOTAL_summer_2003-07-1.nc TOTAL_summer_2003-07-04.nc RAIN_summer_2003-07-04.nc
TOTAL_summer_2003-08-1.nc TOTAL_summer_2003-08-01.nc RAIN_summer_2003-08-01.nc
TOTAL_summer_2003-08-1.nc TOTAL_summer_2003-08-02.nc RAIN_summer_2003-08-02.nc
TOTAL_summer_2003-08-1.nc TOTAL_summer_2003-08-03.nc RAIN_summer_2003-08-03.nc
TOTAL_summer_2003-08-1.nc TOTAL_summer_2003-08-04.nc RAIN_summer_2003-08-04.nc

所以它只是把一个常数1放在那里而不是02, 03, 04 etc.
所以问题是,如何修改脚本,使它在每个循环中只添加+1j

oknwwptz

oknwwptz1#

使用双括号,例如:$((j+1)),尽管这将丢失前导0;如果你知道日期总是1-4,那么你可以在文件名中硬编码0(就像你现在对月份所做的那样)。
假设条件:

  • 你最终需要处理月份10 / 11 / 12,所以你需要一个不同的解决方案,不需要在月份前加上0
  • 我们不需要担心+1天会导致下一个月的滚动(例如,5月31日+1天=> 6月1日);否则我们需要考虑一些额外的代码来处理“日期数学”

与硬编码0不同,我可能会选择使用printf来为个位数的月/日前置一个前导0:

for i in {6..8}
do
    printf -v m "%02d" "${i}"

    for j in {1..4}                     # use {1..3} if no files exist for day #5
    do
        printf -v d1 "%02d" "${j}"
        printf -v d2 "%02d" $((j+1))

        echo cdo sub "TOTAL_summer_2003-${m}-${d2}.nc" "TOTAL_summer_2003-${m}-${d1}.nc" "RAIN_summer_2003-${m}-${d1}.nc"
    done
done

**注意:**一旦对输出感到满意,请删除echo,让脚本执行cdo调用

这产生:

cdo sub TOTAL_summer_2003-06-02.nc TOTAL_summer_2003-06-01.nc RAIN_summer_2003-06-01.nc
cdo sub TOTAL_summer_2003-06-03.nc TOTAL_summer_2003-06-02.nc RAIN_summer_2003-06-02.nc
cdo sub TOTAL_summer_2003-06-04.nc TOTAL_summer_2003-06-03.nc RAIN_summer_2003-06-03.nc
cdo sub TOTAL_summer_2003-06-05.nc TOTAL_summer_2003-06-04.nc RAIN_summer_2003-06-04.nc
cdo sub TOTAL_summer_2003-07-02.nc TOTAL_summer_2003-07-01.nc RAIN_summer_2003-07-01.nc
cdo sub TOTAL_summer_2003-07-03.nc TOTAL_summer_2003-07-02.nc RAIN_summer_2003-07-02.nc
cdo sub TOTAL_summer_2003-07-04.nc TOTAL_summer_2003-07-03.nc RAIN_summer_2003-07-03.nc
cdo sub TOTAL_summer_2003-07-05.nc TOTAL_summer_2003-07-04.nc RAIN_summer_2003-07-04.nc
cdo sub TOTAL_summer_2003-08-02.nc TOTAL_summer_2003-08-01.nc RAIN_summer_2003-08-01.nc
cdo sub TOTAL_summer_2003-08-03.nc TOTAL_summer_2003-08-02.nc RAIN_summer_2003-08-02.nc
cdo sub TOTAL_summer_2003-08-04.nc TOTAL_summer_2003-08-03.nc RAIN_summer_2003-08-03.nc
cdo sub TOTAL_summer_2003-08-05.nc TOTAL_summer_2003-08-04.nc RAIN_summer_2003-08-04.nc
dz6r00yl

dz6r00yl2#

一个月的日子不会在第四天结束。事实上,6月1日至8月31日之间的每一天都被考虑在内。
您可以使用date命令来格式化日期。它还接受相对日期描述,如+ 1 day。也就是说,您可以设置开始日期和结束日期变量,然后在循环中向开始日期添加一天,直到到达结束日期。

start='2003-06-01'; end='2003-08-31'
while next="$(date +%F -d "$start + 1 day")"; test "$start" != "$end"
do
  echo cdo sub "TOTAL_summer_$next.nc" "TOTAL_summer_$start.nc" "RAIN_summer_$start.nc"
  start="$next"
done
cdo sub TOTAL_summer_2003-06-02.nc TOTAL_summer_2003-06-01.nc RAIN_summer_2003-06-01.nc
cdo sub TOTAL_summer_2003-06-03.nc TOTAL_summer_2003-06-02.nc RAIN_summer_2003-06-02.nc
cdo sub TOTAL_summer_2003-06-04.nc TOTAL_summer_2003-06-03.nc RAIN_summer_2003-06-03.nc
cdo sub TOTAL_summer_2003-06-05.nc TOTAL_summer_2003-06-04.nc RAIN_summer_2003-06-04.nc
:
cdo sub TOTAL_summer_2003-08-28.nc TOTAL_summer_2003-08-27.nc RAIN_summer_2003-08-27.nc
cdo sub TOTAL_summer_2003-08-29.nc TOTAL_summer_2003-08-28.nc RAIN_summer_2003-08-28.nc
cdo sub TOTAL_summer_2003-08-30.nc TOTAL_summer_2003-08-29.nc RAIN_summer_2003-08-29.nc
cdo sub TOTAL_summer_2003-08-31.nc TOTAL_summer_2003-08-30.nc RAIN_summer_2003-08-30.nc

或者,您可以在直接迭代文件时使用相同的技术。假设存在文件TOTAL_summer_2003-06-01.ncTOTAL_summer_2003-08-30.nc

for file in TOTAL_summer*.nc
do
  day="${file%.nc}"; day="${day##*_}"; tom="$(date +%F -d "$day + 1 day")"
  echo cdo sub "TOTAL_summer_$tom.nc" "$file" "RAIN_summer_$day.nc"
done
cdo sub TOTAL_summer_2003-06-02.nc TOTAL_summer_2003-06-01.nc RAIN_summer_2003-06-01.nc
cdo sub TOTAL_summer_2003-06-03.nc TOTAL_summer_2003-06-02.nc RAIN_summer_2003-06-02.nc
cdo sub TOTAL_summer_2003-06-04.nc TOTAL_summer_2003-06-03.nc RAIN_summer_2003-06-03.nc
cdo sub TOTAL_summer_2003-06-05.nc TOTAL_summer_2003-06-04.nc RAIN_summer_2003-06-04.nc
:
cdo sub TOTAL_summer_2003-08-28.nc TOTAL_summer_2003-08-27.nc RAIN_summer_2003-08-27.nc
cdo sub TOTAL_summer_2003-08-29.nc TOTAL_summer_2003-08-28.nc RAIN_summer_2003-08-28.nc
cdo sub TOTAL_summer_2003-08-30.nc TOTAL_summer_2003-08-29.nc RAIN_summer_2003-08-29.nc
cdo sub TOTAL_summer_2003-08-31.nc TOTAL_summer_2003-08-30.nc RAIN_summer_2003-08-30.nc
ui7jx7zq

ui7jx7zq3#

这有点过分,但您可以循环遍历文件路径并使用它们填充bash数组,使用日期(转换为纪元时间)作为“索引”。然后循环bash数组中定义的每个“epoch time”,并检查前一天的索引是否存在,在这种情况下,运行cbo命令:

#!/bin/bash

# function Ymd2s()
#     converts "year" "month" "day" (in UTC time) to "seconds since EPOCH"
#     example: Ymd2s 2003 06 01
#      output: 1054425600
Ymd2s() {
    local Y=$1 m=${2#0} d=${3#0} tm_year tm_yday
    local -a month_to_days=( _ 0 31 59 90 120 151 181 212 243 273 304 334 )
    echo "$((
        tm_year = Y - 1900,
        tm_yday = month_to_days[m] + d - 1 + ((m > 2 && (Y%4 == 0 && Y%100 != 0) || Y%400 == 0) ? 1 : 0),
        tm_yday*86400 + (tm_year-70)*31536000 + ((tm_year-69)/4)*86400 - ((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400
    ))"
}

files=()

# FILL THE ARRAY USING EPOCH TIMES AS INDICES
for f in some/path/TOTAL_*.nc
do
    [[ ${f##*/} =~ ([0-9]{4})-([0-9]{2})-([0-9]{2}) ]] || continue

    t=$(Ymd2s "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" "${BASH_REMATCH[3]}")

    files[t]=$f
done

# LOOP THROUGH THE EPOCH TIMES (ARRAY INDICES)
for t1 in "${!files[@]}"
do
    (( t2 = t1 - 86400 ))
    [[ ${files[t2]:+1} ]] || continue

    f1=${files[t1]}
    f2=${files[t2]}

    echo cbo sub "$f1" "$f2" RAIN_"${f1##*TOTAL_}"
done

**备注:**这里我手动转换了日期,进行了一些计算,但你肯定可以使用date命令代替(=>不可移植且较慢)。

示例输出:

cbo sub some/path/TOTAL_summer_2003-06-02.nc some/path/TOTAL_summer_2003-06-01.nc RAIN_summer_2003-06-02.nc
cbo sub some/path/TOTAL_summer_2003-06-03.nc some/path/TOTAL_summer_2003-06-02.nc RAIN_summer_2003-06-03.nc
cbo sub some/path/TOTAL_summer_2003-06-04.nc some/path/TOTAL_summer_2003-06-03.nc RAIN_summer_2003-06-04.nc
cbo sub some/path/TOTAL_summer_2003-07-02.nc some/path/TOTAL_summer_2003-07-01.nc RAIN_summer_2003-07-02.nc
cbo sub some/path/TOTAL_summer_2003-07-03.nc some/path/TOTAL_summer_2003-07-02.nc RAIN_summer_2003-07-03.nc
cbo sub some/path/TOTAL_summer_2003-07-04.nc some/path/TOTAL_summer_2003-07-03.nc RAIN_summer_2003-07-04.nc
cbo sub some/path/TOTAL_summer_2003-08-02.nc some/path/TOTAL_summer_2003-08-01.nc RAIN_summer_2003-08-02.nc
cbo sub some/path/TOTAL_summer_2003-08-03.nc some/path/TOTAL_summer_2003-08-02.nc RAIN_summer_2003-08-03.nc
cbo sub some/path/TOTAL_summer_2003-08-04.nc some/path/TOTAL_summer_2003-08-03.nc RAIN_summer_2003-08-04.nc

相关问题