【问题标题】:Find the next nearest value (bash)查找下一个最接近的值 (bash)
【发布时间】:2021-02-16 17:38:10
【问题描述】:

假设我在列中有一些假期数据 (holiday_master.csv),类似于

...
20200320   Vernal Equinox Day
20200429   Showa Day
20200503   Constitution Day
20200505   Green Day
20200720   Children's Day
20200811   Sea Day
...

鉴于这组数据,我想从给定日期找到下一个最近的假期。 例如,如果输入为20200420,则应为20200429 Showa Day。 如果输入为20200620,则应为20200720 Children's Day。 我觉得 awk 具有执行此操作所需的功能,但欢迎任何在 bash 脚本中工作的解决方案。

【问题讨论】:

  • 您想如何处理同一天发生两个事件的情况?
  • 非常感谢您的迅速回复。我已经对给定的表格进行了更正,因此数据中不会有相同的日期。

标签: linux bash shell unix awk


【解决方案1】:

请您试试bash 脚本:

#!/bin/bash

input="20200428"                        # or assign to whatever
< "holiday_master.csv" sort -nk1,1 |    # sort the csv file by date and pass to the while loop
while read -r date desc; do
    if (( date >= input )); then        # if the date is greater than or equal to the input
        echo "$date" "$desc"            # then print the line
        break                           # and exit the loop
    fi
done

【讨论】:

  • 非常感谢。你的代码对解决我的问题很有帮助。
【解决方案2】:

假设没有两天会有相同的日期......

DATE=<some desired input date>
awk "{print (\$1 - $DATE"' "\t" $0)}' calendar.txt | sed '/^-/d' | sort | head -n 1 | awk '{$1=""; print $0}'

说明

  1. awk "{print (\$1 - $DATE"' "\t" $0)}' calendar.txt:在 input.txt 文件中添加一列,描述所需输入日期和日期列
  2. 之间的差异
  3. sed '/^-/d':删除所有以- 开头的行。负差的日期已经过去。
  4. sort:将剩余条目从最小到最大排序(基于差异列)
  5. head -n 1:只选择第一行(最低差)
  6. awk '{$1=""; print $0}':打印除第一列以外的所有内容

更漂亮的脚本版本

#!/bin/bash
# Usage: script <Date> <Calendar file>
DATE=${1:--1}
CAL=${2:-calendar.txt}

# Arg check and execute
if[ ! -f $CAL ]
then
    echo "File not found: $CAL"
    echo "Usage: script <Date> <Calendar file>"
elif [ $DATE -le 0 ]
then
    echo "Invalid date: $DATE"
    echo "Usage: script <Date> <Calendar file>"
elif [ $(echo "$DATE" | grep -Ewo -- '-?[0-9]+' | wc -l) -eq 0 ]
then
    echo "Invalid date: $DATE"
    echo "Usage: script <Date> <Calendar file>"
else
    awk '{print ($1 - '"$DATE"' "\t" $0)}' $CAL | sed '/^-/d' | sort | head -n 1 | awk '{$1=""; print $0}'
fi

【讨论】:

    【解决方案3】:

    当您使用 YYYYMMDD 格式时,我们可能会将其与数字进行比较(注意:年大于月,月大于日)。所以你可以使用AWK下面的方式,让:

    20200320   Vernal Equinox Day
    20200429   Showa Day
    20200503   Constitution Day
    20200505   Green Day
    20200720   Children's Day
    20200811   Sea Day
    

    然后将文件命名为holidays.txt

    awk 'BEGIN{inputdate=20200420}{if($1>inputdate){print $2;exit}}' holidays.txt
    

    输出:

    Showa
    

    解释:在BEGIN 中我将inputdate 设置为20200420 然后当在1st 列中找到更大数字的行时,我print 2nd 列和exit 的内容(否则稍后日期也会被打印出来)。请注意,AWK 在被要求进行比较时会自动解析数字(在本例中为 &gt;),因此您不必自己关心转换 - 您甚至可以进行 inputdate="20200420",它也可以。

    此解决方案假定文件中的所有日期都已排序。

    【讨论】:

      【解决方案4】:

      使用 awk 并假设源数据以逗号分隔:

      awk -F, -v dayte="20200420" '
                              BEGIN {
                                     "date -d "dayte" +%s" | getline dat1                                 
                                    { 
                                    {
                                     "date -d "$1" +%s" | getline dat2;
                                     dat3=dat2-dat1;
                                     if (dat3 > 0 ) 
                                                   { 
                                                     hols[dat3]=$2 
                                                   } 
                                      } 
                                END { 
                                      asorti(hols,hols1,"@ind_num_asc");
                                      print hols[hols1[1]] 
                                     }
                                ' holiday_master.csv
      

      一个班轮:

      awk -F, -v dayte="20200420" 'BEGIN { "date -d "dayte" +%s" | getline dat1 } { "date -d "$1" +%s" | getline dat2;dat3=dat2-dat1;if (dat3 > 0 ) { hols[dat3]=$2 } } END { asorti(hols,hols1,"@ind_num_asc");print hols[hols1[1]] }' holiday_master.csv
      

      将字段分隔符设置为 ,并将变量 dayte 设置为我们希望检查的日期。在 BEGIN 块中,我们通过 awk 管道/getline 将 dayte 变量传递给 date 命令,并将 epoch 结果读入变量 dat1。我们对主文件 ($1) 的第一列执行相同操作,并将其读入 dat2。我们获取纪元日期之间的差异并将结果读入 dat3。只有当结果为正时(将来),我们才会使用 dat3 作为“hols”数组中的索引,并将假日描述作为值。在 END 块中,我们将 hols 的索引排序到一个 news hols1 数组中,该数组基于升序的数字索引。然后我们取新的 hols1 数组的第一个索引来获得最接近 dayte 变量的假期。

      【讨论】:

        【解决方案5】:

        假设假期列表文件按照您给定的日期排序,以下将起作用

        $ awk  -v dt="20200420" ' (dt-$1)<0 { print;exit }  ' holiday.txt
        20200429   Showa Day
        
        $ awk  -v dt="20200620" ' (dt-$1)<0 { print;exit }  ' holiday.txt
        20200720   Children's Day
        
        $
        

        如果假期文件没有排序,那么可以在下面使用

        $ shuf holiday.txt | awk  -v dt="20200420" ' dt-$1<0 { a[(dt-$1)*-1]=$0 } END { asort(a); print a[1] }  '
        20200429   Showa Day
        
        $ shuf holiday.txt | awk  -v dt="20200620" ' dt-$1<0 { a[(dt-$1)*-1]=$0 } END { asort(a); print a[1] }  '
        20200720   Children's Day
        

        【讨论】:

          猜你喜欢
          • 2014-07-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-08-12
          • 1970-01-01
          • 2013-03-01
          • 1970-01-01
          相关资源
          最近更新 更多