修改文本文件中不是唯一行的字段

时间:2014-10-31 00:15:53

标签: bash sorting unique

我正在处理一个脚本,该脚本需要从单个文本文件中获取重复的行,并更改日期字段上的值,但只更改时间字段。字段分隔符是TAB所以......

# cat enviando4
1414743351      2014-11-01 09:00:00
1414743351      2014-10-31 09:15:51
1414743351      2014-10-30 23:00:00
1414743351      2014-10-31 09:15:51
1414743351      2014-10-30 23:00:00
1414743351      2014-10-31 10:25:00
1414743351      2014-10-31 09:15:51
1414743351      2014-11-01 10:25:00

我按日期排序:

/ bin / sort enviando4 -k2 -t $' \ t' -o enviando4

# cat enviando4
1414743351      2014-10-30 23:00:00
1414743351      2014-10-30 23:00:00
1414743351      2014-10-31 09:15:51
1414743351      2014-10-31 09:15:51
1414743351      2014-10-31 09:15:51
1414743351      2014-10-31 10:25:00
1414743351      2014-11-01 09:00:00
1414743351      2014-11-01 10:25:00

现在我需要向任何重复的日期添加至少4分钟(从不减去),因此我将只有唯一的日期。它看起来像这样:

# cat enviando4
1414743351      2014-10-30 23:04:00 --> add 4
1414743351      2014-10-30 23:00:00 --> no change
1414743351      2014-10-31 09:19:51 --> add 4
1414743351      2014-10-31 09:23:51 --> add 8
1414743351      2014-10-31 09:15:51 --> no change
1414743351      2014-10-31 10:25:00 --> unique, no change 
1414743351      2014-11-01 09:00:00 --> unique, no change
1414743351      2014-11-01 10:25:00 --> unique, no change

并验证这些更改未产生新的重复值。 我坚持这个。 谢谢。

1 个答案:

答案 0 :(得分:0)

你的任务并不困难。 Bash拥有出色的日期操作工具。您需要做的是sort the original列表,然后是read each line已排序文件,compare the date/time to the previous日期时间并使用计数器,将重复时间增加counter * 4min偏移量,并且write the new date/time to your output file.有很多方法可以处理时间调整。最简单的方法是将日期/时间字符串转换为自纪元以来的秒数。然后只需将偏移量添加到重复时间并将其转换回所需的日期/时间格式。

以下示例显示了执行此操作的一种方法。有几个操作可以组合,但我将偏移计算分开,以使其更具可读性。该脚本将输入文件作为第一个参数(我将其默认设置为dat/env4.dat 用于我的测试,并根据需要设置)。然后脚本将分类到临时文件,读取临时文件,将时间调整为重复,然后将输出写入inputfile.out,在退出之前删除临时文件。如果您有任何问题,请与我联系:

#!/bin/bash

ifn="${1:-dat/env4.dat}"            # set input filename (ifn) and validate

[ -r "$ifn" ] || {
    printf "\n  Error: input file not readable. Usage: %s [<filename> (dat/env4.dat)]\n\n" "${0//*\//}" >&2
    exit 1
}

## initialize variables
tfn="/tmp/${ifn//*\//}.tmp"         # set temp filename  (tfn)
ofn="${ifn}.out"                    # set output filename (ofn)
:> "$ofn"                           # truncate output file
pdate=0                             # initialize prior date
cnt=0                               # counter variable
tos=240                             # time offset in seconds (4 min.)
tse=0                               # time since epoch in seconds

sort "$ifn" > "$tfn"                # sort input file into temp file & validate

[ -r "$tfn" ] || {
    printf "\n  Error: sort failed to produce a tmp file or tmp file not readable\n\n" >&2
    exit 1
}

## read temp file into index/idate and add 4 min to each successive duplicate
while read -r index idate || [ -n "$idate" ]; do

    if [ "$pdate" = "$idate" ]; then
        tse=$(date -d "$idate" +%s) # get time since epoch for idate
        cnt=$((cnt+1))              # increase counter
        nos=$((cnt*tos))            # set new time offset (not Nitrous Oxide)
        ntm=$((tse+nos))            # set new time including offset
        # write new time to output
        printf "%s\t%s\n" "$index" "$(date -d "@${ntm}" +"%F %T" )" >> "$ofn"
    else
        cnt=0; nos=0                # reset counter and new time offset
        # write output unchanged
        printf "%s\t%s\n" "$index" "$idate" >> "$ofn"
    fi

    pdate="$idate"                  # save current date/time as prior date/time

done <"$tfn"

[ -r "$tfn" ] && rm "$tfn"          # remove temp file

输入文件:

$ cat dat/env4.dat
1414743351      2014-11-01 09:00:00
1414743351      2014-10-31 09:15:51
1414743351      2014-10-30 23:00:00
1414743351      2014-10-31 09:15:51
1414743351      2014-10-30 23:00:00
1414743351      2014-10-31 10:25:00
1414743351      2014-10-31 09:15:51
1414743351      2014-11-01 10:25:00

输出文件:

$ cat dat/env4.dat.out
1414743351      2014-10-30 23:00:00
1414743351      2014-10-30 23:04:00
1414743351      2014-10-31 09:15:51
1414743351      2014-10-31 09:19:51
1414743351      2014-10-31 09:23:51
1414743351      2014-10-31 10:25:00
1414743351      2014-11-01 09:00:00
1414743351      2014-11-01 10:25:00

注意:如果您想要翻转重复项以便首先显示较大的偏移时间,则应该可以对输出文件进行操作。在offset while loop中执行此操作会使逻辑过于复杂,以达到此问题的目的。如果要在offset while loop中包含附加代码,基本方法是将先前日期和任何匹配日期存储在数组中,然后偏移数组日期/时间值并按相反顺序写出。每次遇到新的日期/时间时都取消设置数组。


包含电子邮件和调整字段的附录

如果您有兴趣添加到输出中,以便在开头添加e-mail,然后在time adjustmentdate portion之间加入time portion {1}},只需在开头添加电子邮件,然后将new date field返回的新字符串拆分为datedate part并插入{{1}即可轻松完成此操作在输出中的两个之间。无论您使用time part还是00:0n:00都没有区别。 printf更加灵活,但有时候echo也会带来优势。

注意:,在下面的代码中,我形成printfecho00:0n:000,假设只有2个重复。如果有3个或更多,如果调整后的时间大于n(例如4, 8, etc..重复00:nn:00),则必须处理此问题以调整逻辑以形成8 minutes

如果您有进一步的问题,请告诉我。

12, 16, 20, ...

输出文件:(使用相同的输入)

3rd, 4th, 5th, ...