【问题标题】:awk output to file based on filterawk 根据过滤器输出到文件
【发布时间】:2021-02-03 18:21:18
【问题描述】:

我有一个很大的CSV 文件,我需要根据其中一列中的值将其切成不同的部分。我的输入文件dataset.csv 是这样的:

注意:已编辑以澄清数据是 ,data, 没有空格。

action,action_type, Result
up,1,stringA
down,1,strinB
left,2,stringC

所以,用action_type 分割我只是这样做(我需要结果文件中的整个匹配行):

awk -F, '$2 ~ /^1$/ {print}' dataset.csv >> 1_dataset.csv
awk -F, '$2 ~ /^2$/ {print}' dataset.csv >> 2_dataset.csv

这按预期工作,但我基本上遍历了我的原始数据集两次。我的原始数据集大约 5GB,我有 30 个action_type 类别。我每天都需要这样做,所以我需要编写脚本让它自己高效地运行。

我尝试了以下方法,但它不起作用:

# This is a file called myFilter.awk

{
action_type=$2;
if (action_type=="1") print $0 >> 1_dataset.csv;
else if (action_type=="2") print $0 >> 2_dataset.csv;
}

然后我运行它:

awk -f myFilter.awk dataset.csv

但我什么也得不到。从字面上看,什么都没有,甚至没有错误。哪一种告诉我我的代码根本不匹配任何东西,或者我的打印/管道语句是错误的。

【问题讨论】:

  • 您的字段分隔符是一个, 还是一个, 后跟一个空格?
  • 如果您在逗号之后和数据之前有一个空格(例如,1 或2),并且您的awk 输入分隔符只是一个逗号,那么您的测试将变为@987654337 @ == 1,这是'假';有关修剪前导/尾随空格的想法,请参阅 this 和 this
  • @Cyrus,这是一个,。谢谢!
  • @markp-fuso,它没有空格。我只是编辑了问题以使其清楚。谢谢!
  • 您希望标题行包含在每个输出文件中吗?你有 GNU awk (awk --version) 吗?

标签: bash csv if-statement awk filter


【解决方案1】:

您可以尝试使用这个 awk 在单个命令中执行此操作:

awk -F, 'NR > 1{fn = $2 "_dataset.csv"; print >> fn; close(fn)}' file

【讨论】:

  • 天哪!这太棒了@anubhava!它完全奏效了!谢谢!
  • 这是一种很棒的内容提取方式。这个技巧的发生是因为print >> fn 部分,它不断地将现有的fn 文件附加为原始file 进度。
  • 只要确保在运行之前删除所有现有的输出文件,否则>> 将附加到该现有文件...
  • 嗨@dawg。是的,谢谢提醒。我还将测试其他方法以找出哪种方法更有效。在我的 5GB 文件中,这已经运行了大约 2 个小时,我认为它甚至还没有完成(基于输出文件的大小,然后它们的总和应该与原始文件的大小匹配)。跨度>
  • @Wilmar 如果您正在寻找最快的解决方案,请更新您的问题以说明这一点。到目前为止,没有人发布最快的解决方案,而且由于您已经接受了答案,因此很有可能没有人会发布。另请参阅我在您的问题下的评论并更新您的问题以根据您发布的示例输入显示预期的输出。
【解决方案2】:

使用 GNU awk 处理许多同时打开的文件,并且不复制每个输出文件中的标题行:

awk -F',' '{print > ($2 "_dataset.csv")}' dataset.csv

或者如果您还希望标题行显示在每个输出文件中,那么使用 GNU awk:

awk -F',' '
    NR==1 { hdr = $0; next }
    !seen[$2]++ { print hdr > ($2 "_dataset.csv") }
    { print > ($2 "_dataset.csv") }
' dataset.csv

或与任何 awk 相同:

awk -F',' '
    NR==1 { hdr = $0; next }
    { out = $2 "_dataset.csv" }
    !seen[$2]++ { print hdr > out }
    { print >> out; close(out) }
' dataset.csv

【讨论】:

    【解决方案3】:

    按照目前的编码,输入字段分隔符尚未定义。

    当前:

    $ cat myfilter.awk
    {
    action_type=$2;
    if (action_type=="1") print $0 >> 1_dataset.csv;
    else if (action_type=="2") print $0 >> 2_dataset.csv;
    }
    

    调用:

    $ awk -f myfilter.awk dataset.csv
    

    有几种方法可以解决这个问题:

    $ awk -v FS="," -f myfilter.awk dataset.csv
    

    或

    $ cat myfilter.awk
    BEGIN {FS=","}
    {
    action_type=$2
    if (action_type=="1") print $0 >> 1_dataset.csv;
    else if (action_type=="2") print $0 >> 2_dataset.csv;
    }
    
    $ awk -f myfilter.awk dataset.csv
    

    【讨论】:

    • 非常感谢@markp-fuso。这确实有效。我 anubhava 'anubhava' 的回答是正确的,因为它简洁明了。
    • @Wilmar 没问题,anubhava 在他的键盘上太快了! :-) 我更感兴趣的是指出原始代码的问题
    • @mark-fuse。当然,这有很大帮助!再次感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-01-28
    • 1970-01-01
    • 1970-01-01
    • 2021-03-29
    • 1970-01-01
    • 2021-07-03
    • 1970-01-01
    相关资源
    最近更新 更多