我是 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 列。
从这个数据集中,
- 查找其中包含单词“read”且分数超过 20 的行。 2. 在这些行中,仅打印分数和 ID 列,并根据分数值排序。
- 将这些排序的列存储在文本文件中。
预期输出是:
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