【问题标题】:How to get a data range in a million rows dataset如何获取一百万行数据集中的数据范围
【发布时间】:2023-03-05 08:07:01
【问题描述】:

我有一个包含数百万行的文件,具有以下模式

01/02/1991,0931,7.13,7.13,7.13,7.13,8000

01/02/1991,0932,7.14,7.14,7.14,7.14,8000

01/02/1991,0935,7.16,7.16,7.16,7.16,3200

01/02/1991,0938,7.16,7.17,7.16,7.17,19200

01/02/1991,0941,7.19,7.19,7.19,7.19,200000 

01/02/1991,0956,7.19,7.19,7.19,7.19,8800

日期格式为mm/dd/YYYY。如何仅获取 01/01/2002 和 08/31/2008 之间的数据范围并删除其他行?日期 01/01/2002 和 08/31/2008 本身可能不在文件中。

我想用 bash 来做

头文件:

01/02/1991,0931,7.13,7.13,7.13,7.13,83200^M$
01/02/1991,0932,7.14,7.14,7.14,7.14,8000^M$
01/02/1991,0935,7.16,7.16,7.16,7.16,3200^M$
01/02/1991,0938,7.16,7.17,7.16,7.17,19200^M$
01/02/1991,0941,7.19,7.19,7.19,7.19,200000^M$
01/02/1991,0956,7.19,7.19,7.19,7.19,8800^M$
01/02/1991,0957,7.20,7.20,7.20,7.20,13600^M$
01/02/1991,0958,7.22,7.22,7.22,7.22,5600^M$
01/02/1991,1003,7.22,7.23,7.22,7.23,8000^M$
01/02/1991,1006,7.23,7.23,7.23,7.23,10400^M$

【问题讨论】:

  • 记录是否已经按日期排序?
  • 是的,它们已经排序了
  • 这些行真的是这样的双倍行距吗?顺便说一句,那不是bash,而是sed。而你的“尝试”是荒谬的。你读过说明书吗?
  • 我是 sed 和 awk 的新手,我在这里发布它只是因为我对尝试不同的命令感到沮丧。我知道这是一个荒谬的例子,但我把它放在那里只是为了表明我做了功课。是的,文件中间没有那个空间
  • 我还需要中间的行,不仅是与这两个日期相关的行,我稍后会尝试

标签: bash text awk sed grep


【解决方案1】:

使用awk 你可以做到:

awk -F, '$1=="01/02/2002"{p=1} $1=="01/08/2008"{p=2} $1!="01/08/2008" && p==2{exit} p' dataset.txt

【讨论】:

  • 太糟糕了,日期没有以合理的 YYYY-mm-dd 格式格式化,所以你可以写 $1 > "2008-08-31" {exit}
  • 是的,如果有的话会很好。
  • @anubhava 非常感谢您的帮助。但是我应该说它没有做任何事情。它遍历文件,但在进程结束时它具有相同的行数。
  • @QuentinTanioartino 您需要将输出重定向到另一个文件。
  • 正如我之前怀疑的那样,您的输入文件中不存在两个日期01/01/2002 or 31/08/2008。试试这个命令让它工作:awk -F, '$1=="01/02/2002"{p=1} p; $1=="01/08/2008"{exit}' AA.txt
【解决方案2】:
awk -F, '$1=="01/01/2002",$1=="31/08/2008" {print;next} $1=="31/08/2008" {print;next} {quit}' file

添加了额外的$1=="31/08/2008" 以打印具有该日期的所有记录(不仅仅是第一个)。并添加了退出以提高效率。改进完全归功于 anubhava。

【讨论】:

  • 简单但不起作用(它只会打印日期为"31/08/2008"的第一条记录
  • 否则不会发表评论。
  • @anubhava 哦,我明白你的意思了。对不起。 :-(
  • 它现在可以工作,但由于 OP 谈到了百万行,一旦记录超过 "31/08/2008",最好调用 exit
  • @anubhava 好点。现在我明白你的答案的复杂性了。
【解决方案3】:

sed 提案:

sed -n '\#01/01/2002#,\#31/08/2008#{p;d}; \#31/08/2008#p' \
   dataset.txt > newFile.txt

当线条在图案之间时,打印,从图案空间中删除并退出。由于d,第一行结束模式退出,所以只有一个打印。使用第二个命令打印以下结束模式行。

【讨论】:

  • 但这不会只打印第二个日期的第一条记录吗?如果该日期有多条记录怎么办?
  • @ooga:所有这些记录都是为我打印的(这就是我使用{N,p} 的原因)。你试过了吗?
  • 你抓住了我!我没有运行它。但是现在我这样做了,它似乎只打印了第二个日期的记录的一个额外重复。即,如果有 3 个或更多记录的结束日期,它只打印前两个。不过,我正在删除我的反对票,因为我在不运行它的情况下这样做是粗心的。 (编辑:显然你不能在一定时间后删除反对票。如果你编辑它,我想我可以。也许你可以修复它。)
  • 这是一种修复方法:sed -n '\#01/01/2002#,\#31/08/2008#{p;d}; \#31/08/2008#p' file > outfile
  • @ooga:你说得对,我测试了我的代码,但似乎这还不够。我用你的修复编辑我的帖子。谢谢!
【解决方案4】:

这里有一个替代方法:将日期与时间进行比较。这将比 anubhava 的解决方案慢很多。需要 GNU awk:

gawk -F, -v start_date=01/01/2002 -v end_date=08/31/2008 '
    function to_epoch(date) {
        #             ... year .....     ... month ......     ... day ........
        return mktime(substr(date,7) " " substr(date,1,2) " " substr(date,4,2) " 0 0 0")
    }
    BEGIN { start = to_epoch(start_date); end = to_epoch(end_date) }
    { t = to_epoch($1) }
    start <= t && t <= end
    t > end {exit}
' file

【讨论】:

  • 女士们,先生们,我们有一个赢家......有些担忧。您的脚本是唯一正常工作的脚本....但是,脚本从 01/01/2000 而不是 2002 开始获取数据。finisch 19/01/2007 而不是 2008
  • 嗯,不在我的测试中。你能展示一个最小输入样本来演示这个问题吗?
  • 好的,我编辑了答案。在您的问题中,您告诉我们日期格式是dd/mm/YYYY——实际上是mm/dd/YYYY。所以31/08/2008 永远不会出现在文件中!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多