【问题标题】:Splitting CSV file and excluding column in output using bash, sed or awk使用 bash、sed 或 awk 拆分 CSV 文件并排除输出中的列
【发布时间】:2012-04-30 08:28:09
【问题描述】:

我有一个 CSV 文件,其中包含如下数据:-

1,275,,,275,17.3,0,"2011-05-09 20:21:45"
2,279,,,279,17.3,0,"2011-05-10 20:21:52"
3,276,,,276,17.3,0,"2011-05-11 20:21:58"
4,272,,,272,17.3,0,"2011-05-12 20:22:04"
5,272,,,272,17.3,0,"2011-05-13 20:22:10"
6,278,,,278,17.3,0,"2011-05-13 20:24:08"
7,270,,,270,17.3,0,"2011-05-13 20:24:14"
8,269,,,269,17.3,0,"2011-05-14 20:24:20"
9,278,,,278,17.3,0,"2011-05-14 20:24:26"

此文件包含 4432986 行数据。

我希望根据最后一列中的日期将新文件名拆分出来。

因此,根据上面的数据,我想要 6 个新文件,每个文件中每天都有行。

我想要以 YYYY_MM_DD 格式命名的文件。

我也想忽略输出数据中的第一列

因此文件 2011_05_13 将包含以下行,第一列除外:-

272,,,272,17.3,0,"2011-05-13 20:22:10"
278,,,278,17.3,0,"2011-05-13 20:24:08"
270,,,270,17.3,0,"2011-05-13 20:24:14"

我打算在 linux 机器上执行此操作,所以使用任何 linux 实用程序的任何东西都会很酷,sed awk 等??

【问题讨论】:

  • Sed 似乎是个不错的选择。向我们展示您的尝试。
  • @wildplasser 还没有尝试过,不知道从哪里开始。
  • 好吧,从 sed 手册开始。尝试找到一种方法来执行搜索和替换。
  • cut 实用程序不会处理带引号的逗号,请小心。
  • 请参阅下面的 orangeoctopus 帖子,已经尝试过,它可以工作,但速度很慢。一个 awk one 班轮会很好。

标签: linux bash csv sed awk


【解决方案1】:

这是awk 为您准备的单线:

awk -F "," '{ split ($8,array," "); sub ("\"","",array[1]); sub (NR,"",$0); sub (",","",$0); print $0 > array[1] }' file.txt

达到了预期的输出,尽管也许其中一些代码可以更简洁。 HTH。

编辑:

从左到右读取代码:

  • -F ","
    是的,这设置了分隔符。

  • split ($8,array," ")
    这会拆分空间上的第八列,并将此信息放入名为array 的数组中。

  • sub ("\"","",array[1])
    我们取第一个数组元素(这是一个将成为我们的输出文件名的切片)并替换掉前面的 " 符号(我们需要转义 " 符号,所以我们将 \ 字符放在前面) .

  • sub (NR,"",$0)
    这可以方便地从文件开头删除行号(NR 是行号,$0 当然是分隔之前的整行输入)。

  • sub (",","",$0)
    这将删除行号后的逗号。

  • 现在我们有了干净的文件名和干净的数据行,我们可以将$0 写入array[1]print $0 > array[1]

修复:

因此,如果您更喜欢下划线而不是hypon,我们只需要修复array[1]。我刚刚添加了一个全局替换:gsub ("-","_",array[1])

更新后的代码是:

awk -F "," '{ split ($8,array," "); sub ("\"","",array[1]); gsub ("-","_",array[1]); sub (NR,"",$0); sub (",","",$0); print $0 > array[1] }' file.txt

HTH。

【讨论】:

  • 查看我的 cmets 关于上面的文件名输出
  • 您能解释一下上面的内容以帮助我理解吗?我知道 -F "," 告诉它用逗号分隔 - 我不确定其余的 - 谢谢。
  • 工作得很好,除了在 yyyy-mm-dd 中生成文件,我想用下划线替换破折号。
  • 通过阅读一些 awk 手册了解了它的工作原理。非常感谢。这似乎是最优雅的解决方案,因为我最初正在寻找 awk 解决方案。
  • 不用担心。我很高兴能帮上忙 :-)
【解决方案2】:

这可能对你有用:

sed 's/^[^,]*,\(.*"\(....\)-\(..\)-\(..\).*\)/echo \1 >>\2_\3_\4.csv/' file | sh

或 GNU sed:

sed 's/^[^,]*,\(.*"\(....\)-\(..\)-\(..\).*\)/echo \1 >>\2_\3_\4.csv/e' file

【讨论】:

    【解决方案3】:

    你可以使用这个 awk 命令:

    awk -F, 'BEGIN{OFS=",";} {dt=$8; gsub(/^"| .*"$/,"", dt);
    $1=""; sub(/^,/, "", $0); print $0 > dt}' input.txt
    

    【讨论】:

      【解决方案4】:

      一定很简单

      $ sed 's/^[0-9]*,//' your_gigantic_data.csv
      

      【讨论】:

      • 对不起,我不明白你的回答?
      • sed 命令将删除所有带逗号的起始行号。
      【解决方案5】:

      脚本语言(perl/python)可能是您最好的选择,但我喜欢在 bash 中执行此操作的挑战,所以就在这里。

       cat bigfile.txt | while read LINE;
        do echo $LINE >> `echo $LINE | cut -d, -f8 | cut -c2-11`.txt ;
       done
      

      基本上,它的作用是在while 循环中逐行读取文件,然后根据日期将该行附加到文件中。

      日期是通过两个cut 命令的组合来提取的。第一个 cut 使用逗号分隔符 (-d,) 拉出最后一列(第 8 列),然后第二个 cut 通过删除第一个 " 仅拉出日期,然后直到字符 11。


      现在,解决第一列的删除问题:

      cat bigfile.txt | sed 's/^.*?,//'
      

      这个正则表达式只是删除第一个逗号之前的所有内容。

      因此,我们将用这个替换 while 循环的开头,留下:

       cat bigfile.txt | sed 's/^.*?,//' | while read LINE;
        do echo $LINE >> `echo $LINE | cut -d, -f8 | cut -c2-11`.txt ;
       done
      

      【讨论】:

      • 不错的答案,但我更喜欢切换 sed 来删除第一列。
      • 基于此,设法做到了这样:- head -10 out.csv | sed 1d |切-d, -f2- |一边读线;回声 $LINE >> echo $LINE | cut -d, -f7 | cut -c2-11 | sed s/-/_/g;做了什么改进???
      • 忽略头部-10,仅用于测试目的。必须使用 sed 1d 删除第一行文件,并在最后使用 sed 用下划线替换破折号。有人提出更优雅的解决方案吗?
      • 此解决方案每写入一行打开一次结果文件,但只读取输入文件一次。如果您的输入文件读取速度相当不错(KB 范围或更高),您将需要像@Demosthenex 建议的那样使用一系列 grep。
      • 虽然这种方法有效,但正如@thiton 解释的那样,它很慢。我已将 steve 的 awk 解决方案标记为答案,因为这似乎更接近我真正想要的。
      【解决方案6】:

      这个怪物会抓取所有唯一的日期,然后用 grep 查找原始文件中的这些键,并将它们保存到由该键命名的文件中。是的,猫没用,但试图原子化动作。

      cat records.txt \
      | cut -f8 -d, \
      | cut -f1 -d ' ' \
      | tr -d '"' \
      | sort -u \
      | while read DATE ; do \
          cat records.txt \
          | cut -f2- -d, \
          | egrep ",\"${DATE} [0-9]{2}:[0-9]{2}:[0-9]{2}\"" \
          > ${DATE}.txt
      done
      

      【讨论】:

      • 不,它与您的日期格式不匹配,但重命名是微不足道的。但是考虑到您可能拥有的文件数量,我建议您重新考虑保留 YYYY/MM/DD 格式。
      • 啊,我也忽略了这一点。无论如何,我更喜欢年份,所以它分类得很好。
      猜你喜欢
      • 1970-01-01
      • 2017-08-25
      • 2018-05-01
      • 1970-01-01
      • 2013-01-07
      • 1970-01-01
      • 2013-03-04
      • 2019-12-23
      • 1970-01-01
      相关资源
      最近更新 更多