You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Unix命令填补文件中同姓名年龄记录的日期间隙

需求与问题

需求描述

找出文件中姓名和年龄相同但日期不同的记录,填补相邻记录间的日期间隙,填充的间隙记录沿用前一条的职位信息,同时支持跨月场景(如9月30日到10月4日)。

示例数据(file.txt)

20230907,Allan,29,Marketing
20230912,Allan,29,VirtualAssistant
20230913,Allan,29,Programmer
20230920,Daniel,28,Engineer
20230922,Daniel,28, Photographer

当前代码的问题

现有代码未实现日期间隙填充逻辑,且通过循环调用外部命令的方式处理大文件时效率极低:

#create zero byte file for all filled gaps
cat /dev/null > fillGap.txt
For line in `awk -F"," '{print $2","$3}' file.txt`;do
#if name,age NOT found in fillGap.txt then grep everything that matches in file.txt
if [[ -z `grep -w ${line} fillGap.txt` ]];then
grep -w ${line} file.txt > MatchNameAge.txt
#this is the part of checking if there is a gap between dates and if so, gaps will be filled. I haven't figured it out on how I should do it. maybe you could help me
#after filling the gap, the transformed will be appended in fileGap.txt
else
  #if name,age have already found in filledGap.txt, there's nothing to do.
fi
done

高效解决方案:使用AWK实现

下面的AWK脚本可单进程高效处理需求,支持跨月、闰年等日期场景,无需频繁调用外部命令:

BEGIN {
    FS = ","
    OFS = ","
}

# 按姓名+年龄分组存储所有记录
{
    key = $2 "," $3
    records[key][++count[key]] = $0
}

END {
    # 遍历每个姓名+年龄分组
    for (key in records) {
        record_num = count[key]
        # 提取分组内的日期和完整记录,用于排序
        for (i = 1; i <= record_num; i++) {
            split(records[key][i], fields, ",")
            dates[i] = fields[1]
            lines[i] = records[key][i]
        }
        # 对分组内的记录按日期升序排序(兼容输入无序的情况)
        for (i = 1; i < record_num; i++) {
            for (j = i+1; j <= record_num; j++) {
                if (dates[i] > dates[j]) {
                    temp = dates[i]; dates[i] = dates[j]; dates[j] = temp
                    temp = lines[i]; lines[i] = lines[j]; lines[j] = temp
                }
            }
        }
        # 处理分组内的相邻记录,填充日期间隙
        for (i = 1; i < record_num; i++) {
            split(lines[i], prev_fields, ",")
            split(lines[i+1], curr_fields, ",")
            
            # 解析前后日期为年、月、日数值
            prev_year = substr(prev_fields[1], 1, 4)
            prev_month = substr(prev_fields[1], 5, 2) + 0
            prev_day = substr(prev_fields[1], 7, 2) + 0
            
            curr_year = substr(curr_fields[1], 1, 4)
            curr_month = substr(curr_fields[1], 5, 2) + 0
            curr_day = substr(curr_fields[1], 7, 2) + 0
            
            # 从当前记录的下一天开始填充
            curr_fill_year = prev_year
            curr_fill_month = prev_month
            curr_fill_day = prev_day + 1
            
            # 定义各月份天数,处理闰年2月
            days_in_month[1] = 31
            days_in_month[2] = (curr_fill_year % 4 == 0 && curr_fill_year % 100 != 0) || (curr_fill_year % 400 == 0) ? 29 : 28
            days_in_month[3] = 31
            days_in_month[4] = 30
            days_in_month[5] = 31
            days_in_month[6] = 30
            days_in_month[7] = 31
            days_in_month[8] = 31
            days_in_month[9] = 30
            days_in_month[10] = 31
            days_in_month[11] = 30
            days_in_month[12] = 31
            
            # 循环填充间隙直到到达下一条记录的日期
            while (1) {
                fill_date = sprintf("%04d%02d%02d", curr_fill_year, curr_fill_month, curr_fill_day)
                if (fill_date >= curr_fields[1]) break
                
                # 输出填充记录
                print fill_date, prev_fields[2], prev_fields[3], prev_fields[4]
                
                # 递增加日期,处理跨月/跨年
                curr_fill_day++
                if (curr_fill_day > days_in_month[curr_fill_month]) {
                    curr_fill_day = 1
                    curr_fill_month++
                    if (curr_fill_month > 12) {
                        curr_fill_month = 1
                        curr_fill_year++
                        # 更新闰年2月天数
                        days_in_month[2] = (curr_fill_year % 4 == 0 && curr_fill_year % 100 != 0) || (curr_fill_year % 400 == 0) ? 29 : 28
                    }
                }
            }
            # 输出当前记录
            print lines[i]
        }
        # 输出分组的最后一条记录
        print lines[record_num]
    }
}

使用方法

将脚本保存为fill_gaps.awk,执行以下命令生成结果文件:

awk -f fill_gaps.awk file.txt > fillGap.txt

预期输出

针对示例数据,输出结果如下:

20230907,Allan,29,Marketing
20230908,Allan,29,Marketing
20230909,Allan,29,Marketing
20230910,Allan,29,Marketing
20230911,Allan,29,Marketing
20230912,Allan,29,VirtualAssistant
20230913,Allan,29,Programmer
20230914,Allan,29,Programmer
20230915,Allan,29,Programmer
20230916,Allan,29,Programmer
20230917,Allan,29,Programmer
20230918,Allan,29,Programmer
20230919,Allan,29,Programmer
20230920,Daniel,28,Engineer
20230921,Daniel,28,Engineer
20230922,Daniel,28, Photographer

方案优势

  • 高效性:单进程处理,避免循环调用外部命令,大文件场景下性能远超原有方案
  • 兼容性:完美支持跨月、跨年、闰年等复杂日期场景
  • 鲁棒性:自动对分组内记录按日期排序,即使输入文件记录无序也能正确处理

内容的提问来源于stack exchange,提问作者Kisses

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 14:37:19