如何用上一行的数据替换没有数据的行

如何用上一行的数据替换没有数据的行

输入

Time      Value  Flag
06:15:10  49.95  Actual
00:00:00  0.00  NoValue
06:22:50  49.94  Actual
06:23:00  49.93  Actual
06:23:10  49.93  Actual
06:23:20  49.93  Actual
06:23:30  49.93  Actual
06:24:40  49.92  Actual
00:00:00  0.00  NoValue

我必须替换包含“NoValue”的行。时间将替换为最后记录的时间,增量为 10 秒 (10 秒) 值将替换为最后记录的时间 标志将替换为实际值

我的结果将显示为,

Time      Value  Flag
06:15:10  49.95  Actual
06:15:20  49.95  Actual
06:22:50  49.94  Actual
06:23:00  49.93  Actual
06:23:10  49.93  Actual
06:23:20  49.93  Actual
06:23:30  49.93  Actual
06:24:40  49.92  Actual
06:24:50  49.92  Actual

答案1

awk -F'[: ]+' -v addSec=10 '
 NR>1 && /Actual/{
     sec=(($1*3600)+($2*60)+$3) +addSec;
     prevTime=sprintf("%02d:%02d:%02d", sec/3600, sec%3600/60, sec%60) OFS $4 OFS $5;
 }
 /NoValue/{ $0=prevTime }1
' infile

答案2

尝试这个:

猫诺瓦| tr-s“”| awk -F"[:]" -f val.awk

在哪里:

cat noval 
06:15:10  49.95  Actual
00:00:00  0.00  
06:22:50  49.94  Actual
06:23:00  49.93  Actual
06:23:10  49.93  Actual
06:23:20  49.93  Actual
06:23:30  49.93  Actual
06:24:40  49.92  Actual
00:00:00  0.00  

cat val.awk
{
    if($5=="") {
        print g
                   }
        else {
               print $0
           $3=$3+10
               if ($3>59){
        $3=$3-60
        $2=$2+1
               }
               if ($2>59){
                  $2=$2-60
                  $1=$1+1
               }
if(length($1)<2) {$1="0"$1}
if(length($2)<2) {$2="0"$2}
if(length($3)<2) {$3="0"$3}
               g=$1":"$2":"$3" "$4" "$5
              }
}

结果是:

06:15:10 49.95 Actual
06:15:20 49.95 Actual
06:22:50 49.94 Actual
06:23:00 49.93 Actual
06:23:10 49.93 Actual
06:23:20 49.93 Actual
06:23:30 49.93 Actual
06:24:40 49.92 Actual
06:24:50 49.92 Actual

注意:使用 awk,我们沿着字符冒号 (:) 和空格分解每一行。这样我们就可以访问时间戳的三个组成部分(第 1、2、3 列),以便可能加 10。我们使用 tr 将多个空格压缩为一个。 awk 中的 F 标志被设置为沿着冒号和/或空格分解行以进行操作。

答案3

如果不知道时间戳适用的日期和时区,并且使用理解日期和时间的实用程序(即不仅仅是简单的数学),则无法通过在现有时间上添加 10 秒来确定新时间,因为新时间是以下结果的结果在给定时间上添加 10 秒会受到夏令时和闰秒的影响。

假设您输入时间戳的开始日期是今天,然后使用 GNU awk 来处理时间函数(它处理 DST,但与处理 POSIX 纪元时间的所有工具一样,不处理闰秒,所以希望您不关心这一点) ):

$ cat tst.awk
BEGIN {
    OFS = "  "
    prevDate = (date=="" ? strftime("%Y %m %d") : date)
}
NR == 1 {
    print
    next
}
$3 == "NoValue" {
    prevTime = gensub(/:/," ","g",prevLine[1])
    prevSecs = mktime(prevDate " " prevTime)
    currSecs = prevSecs + 10
    prevDate = strftime("%Y %m %d",currSecs)
    $1 = strftime("%T",currSecs)
    $2 = prevLine[2]
    $3 = prevLine[3]
}
{
    print
    split($0,prevLine)
}

$ awk -f tst.awk file
Time      Value  Flag
06:15:10  49.95  Actual
06:15:20  49.95  Actual
06:22:50  49.94  Actual
06:23:00  49.93  Actual
06:23:10  49.93  Actual
06:23:20  49.93  Actual
06:23:30  49.93  Actual
06:24:40  49.92  Actual
06:24:50  49.92  Actual

如果您希望在计算机设置的时区之外的其他时区应用时间计算,请在执行上述操作之前适当设置 shell 变量,或者在对和TZ的调用上设置 UTC 标志,请参阅mktime()strftime()https://www.gnu.org/software/gawk/manual/gawk.html#Time-Functions

如果您想使用与今天不同的开始日期,请调用脚本以awk -v date='2021 10 03' -f tst.awk file提供您喜欢的YYYY MM DD格式的任何日期。

上面假设时间戳将始终填充在输入的第二行中,因为您没有说明如何处理它。

请注意,正如 @PhilipCouling 在评论(或任何其他库)中指出的那样,mktime()仅给出日期和时间无法可靠地返回自纪元以来的秒数,对于在 DST 结束时的转换间隔期间具有 DST 的时区(DST 开始时很好) )。他们提供的例子是:

在英国,日期/时间 2022 年 10 月 30 日上午 01:30:00 将发生两次。这是因为,当时钟到达凌晨 2 点时,DST 将结束,时钟会向后跳一小时至凌晨 1 点。因此,1:30 在 DST 结束之前发生一次,在 DST 结束之后发生一次。该文件不包含有关它描述的这两者中哪一个的任何信息。该文件不会告诉您 DST 是否已结束。

答案4

使用(以前称为 Perl_6)

~$ raku -e 'my @init = [Z=>] lines[0].words, (DateTime.new("2024-01-01T00:00:00Z"), "0.00", "Initial"); 
            put @init.map(*.key).join("\t"); 
            for lines.map(*.words) -> ($t,$v,$f) { 
                if $f eq "NoValue" { 
                    put join "\t", @init[0].value.hh-mm-ss, @init[1..*].map(*.value) andthen 
                    @init[0] = @init[0].key => @init[0].value.later(:10seconds); 
                } else { 
                    put join "\t", ($t,$v,$f) andthen  
                    @init = [Z=>] 
                            @init.map(*.key), 
                            (DateTime.new("2024-01-01T" ~ $t ~ "Z").later(:10seconds),$v,$f) 
                        } 
                };'  file.txt

Raku 是 Perl 系列中的一种编程语言,具有DateTime内置 ISO 8601 对象。上面我们将初始行 ( line[0]) 作为标头读取,并使用初始值(包括初始时间戳)创建键/值对DateTime。归约元运算符[Z=>]采用其后面的两个列表,并将它们“压缩”在一起作为键/值对,并将其分配给数组@init(即对数组)。这会立即输出put(在\t选项卡上连接),以重建标题行。

从这里我们迭代lines.每行都被映射并分解为words(即列),这些行被分配给临时$t,$v,$f变量以在块内使用:

  • 如果$f标志字符串等于“NoValue” ,则输出eq其中的值。@init然后我们增加时间戳。
  • 如果$f标志ne字符串不等于“NoValue”,则($t,$v,$f)输出该行的值,并@init使用这些新值更新数组($t,$v,$f),这些新值将替换默认/旧值。然后时间戳会递增。

Raku 的一个优点是,DateTime此类函数later(:10seconds)可用于在时间戳上添加 10 秒,以便在下一个“NoValue”标记行中进行插补。还hh-mm-ss允许您仅返回时间部分(请注意,我们使用任意日期2024-01-01,因为这最终会被丢弃)。

示例输入(OP 的示例输入,NoValue末尾有额外的行):

Time      Value  Flag
06:15:10  49.95  Actual
00:00:00  0.00  NoValue
06:22:50  49.94  Actual
06:23:00  49.93  Actual
06:23:10  49.93  Actual
06:23:20  49.93  Actual
06:23:30  49.93  Actual
06:24:40  49.92  Actual
00:00:00  0.00  NoValue
00:00:00  0.00  NoValue

示例输出 1(来自上面):

Time    Value   Flag
06:15:10    49.95   Actual
06:15:20    49.95   Actual
06:22:50    49.94   Actual
06:23:00    49.93   Actual
06:23:10    49.93   Actual
06:23:20    49.93   Actual
06:23:30    49.93   Actual
06:24:40    49.92   Actual
06:24:50    49.92   Actual
06:25:00    49.92   Actual

[上面的注释:样本输入末尾的多个连续“NoValue”行的时间戳正确递增]。


测试“NoValue”初始数据行:为了确定,下面我们可以删除第一个 ( Actual) 数据行,使其00:00:00 0.00 NoValue成为第一个数据行。

示例输出 2(来自上面的示例输入,减去第一个/Actual数据行):

Time    Value   Flag
00:00:00    0.00    Initial
06:22:50    49.94   Actual
06:23:00    49.93   Actual
06:23:10    49.93   Actual
06:23:20    49.93   Actual
06:23:30    49.93   Actual
06:24:40    49.92   Actual
06:24:50    49.92   Actual
06:25:00    49.92   Actual

以上处理正确并报告Initial已估算(人工)值。

https://www.iso.org/iso-8601-date-and-time-format.html
https://docs.raku.org/type/DateTime
https://raku.org

相关内容