过滤 CSV 数据集以查找行并将其存储在文本文件中

过滤 CSV 数据集以查找行并将其存储在文本文件中

我是 shell 命令的新手。我有点纠结这个基于 CSV 数据集 fbnews.csv 的问题。

CSV 数据集如下所示:

D,E,F,   message,                 score,    A,B,C,   ID
d,e,f,  Let's read a book,           24,    a,b,c,    1
j,k,l,   Read this book,             39,    d,e,f,    2
m,n,o,   Have you read this book?,   15,    g,h,i,    3

这只是一个示例。原始数据集包含 20,000,000 行和 20 列。

从这个数据集中,

  1. 查找其中包含单词“read”且分数超过 20 的行。 2. 在这些行中,仅打印分数和 ID 列,并根据分数值排序。
  2. 将这些排序的列存储在文本文件中。

预期输出是:

Score   ID
24      1
39      2

我如何使用 shell 命令来做到这一点?

答案1

使用米勒(https://github.com/johnkerl/miller)并从

D,E,F,message,score,A,B,C,ID
d,e,f,Let's read a book,24,a,b,c,1
j,k,l,Read this book,39,d,e,f,2
m,n,o,Have you read this book?,15,g,h,i,3

和跑步

mlr --csv filter -S '$message=~"(r|R)ead" && $score>20' then cut -f score,ID input.csv >output.csv

你将会拥有

score,ID
24,1
39,2

有关该命令的一些详细信息:

  • --csv,设置输入输出格式
  • filter -S '$message=~"(r|R)ead" && $score>20'应用您的过滤器
  • cut -f score,ID选择您的字段

如果您有一个错误的 CSV,其单元格数量多于标题列,如这个

D,E,F,message,score,A,B,C,ID
d,e,f,Let's read a book,24,a,b,c,1
j,k,l,Read this book,39,d,e,f,2,a wrong cell,another wrong cell
m,n,o,Have you read this book?,15,g,h,i,3

您可以应用ragged选项并运行

mlr --csv --ragged unsparsify then filter -S '$message=~"(r|R)ead" && $score>20' then cut -f score,ID input.csv>output.csv

但是,如果您的 CSV 有问题,最好在此处完全共享

答案2

我正在学习awk,所以我期待智者的反馈:

cat file | tr -s ' ' | awk -F, 'BEGIN { print "Score ID" } tolower($4) ~ /read/ { if($5 >= 20) print $5,$9 }' > output

在这种情况下,为了能够使用 OP 的格式,请将所有空格更改为一个

tr -s ' '

使用逗号作为分隔符:

-F,

要使比较不区分大小写:

tolower($4)

第四列有字符串“read”

tolower($4) ~ /read/

如果第五列的值等于或大于 20,则打印:

if($5>=20) print $5,$9

添加标题(我现在正在尝试使用 执行此操作awk

 BEGIN { print "Score ID" }

输出

score ID
 24  1
 39  2

答案3

我使用 shell 脚本的次数不多,但我经常用其他语言做类似的事情。我将提供一些东西来帮助您组织搜索。

1 - 您需要解析 csv 文件

您可以在此链接中了解如何解析 csv 文件: https://stackoverflow.com/questions/4286469/how-to-parse-a-csv-file-in-bash

2 - 您需要获取与单词“read”匹配的行

您可以使用这样的正则表达式并调整一些标准来捕获大于 20.2 的分数:

/\b(\w*read\w*)\b/g

将其放入此站点,以获取有关表达式的信息:https://regexr.com/

3 - 您需要根据条件对输出进行排序

您可以使用种类命令来执行此操作。它比分配给数组并对该数组进行排序更容易。

4 - 重定向输出

您可以轻松地将 shell 输出重定向到类似“script.sh > my_output.txt”的文件。或者在脚本“var > output.txt”中执行此操作

答案4

一点点awk正则表达式,然后通过管道清理空白column

awk -F',' '{if ( $4 ~ /[Rr]ead/ &&  $5 > 20 || NR==1) print $5, $9}' data.csv | column -t

解释....将字段分隔符设置为 , 后-F','

~....如果第四个字段的正则表达式与“Read”或“read”匹配,并且&&第五个字段> 20,或者||我们位于第一行(带有标题),NR==1则打印出您感兴趣的列。 ....

只是为了好玩

如果您知道列标题但懒得数......

将标头加载到关联数组中

declare -A HEADS=( [mess]=mess [id]=ID [score]=score )

.....awk将数据文件第一行的列索引放入数组中

for j in "${!HEADS[@]}"; do HEADS[$j]=$(awk -F',' -v s=${HEADS[$j]} 'NR==1 {for (i=1; i<=NF; ++i) { if ($i ~ s ) print i }}' data.csv) ; done

...回到顶部只是将索引awk作为变量注入

awk -v mess=${HEADS[mess]} -v score=${HEADS[score]} -v id=${HEADS[id]} -F',' '{if ( $mess ~ /[Rr]ead/ &&  $score >20 || NR==1) print $score, $id}' data.csv | column -t

相关内容