在 CSV 中搜索多个值并从中获取关联值

在 CSV 中搜索多个值并从中获取关联值

我有一个文件.csv

"ItemNo","Name","Weight"
"a001","Item a","1.1"
"a002","Item x","1.2"
"a003","Item_4","1.0"
"a004","Item b","1.1"
"a005","Itemb2","2.0"
"a006","a004","2.0"

我还有几个项目编号.csv

"a003"
"a001"
"a004"

我正在寻找一个命令来创建与“ItemNo”关联的“名称”列表...

所以我的输出.csv应该

"Item_4"
"Item a"
"Item b"

有人可以帮忙吗?


第一列中 file.csv 的每个 item.no 都是唯一的。但有 a001、a001-b1、a001-b2 等等。但是如果您搜索“a001”、“a001-b1”...一切都应该再次是唯一的。

我不需要特定的工具..每个有用的解决方案都可以。但如果只搜索第一行就好了(假设 ItemNo“a006”(第 1 列)的 Item.Name 是“a004”(第 2 列))。


我尝试过grep 命令

grep -f itemno.csv file.csv | awk -F, '{print $2}'

结果只是最后一行的输出:

"Item b"

我尝试过awk 命令

awk -F, 'NR==FNR{a[$1]; next} $1 in a{print $2}' itemno.csv file.csv

结果只是最后一行的输出:

"Item b"

也许循环命令是一个更好的主意?

所以我尝试了这个循环

while read -r line; do
    grep "${line}" file.csv | awk -F "," '{print $2}';
done < itemno.csv 

但有无输出...好像每一行后面都有另一行\r

所以我尝试了这个命令

while read line; do
    grep $(printf ${line} | sed 's/\r//g') file.csv | awk -F "," '{print $2}';
done < itemno2.csv 

有了这个项目号2.csv

"a003"
"a001"
"a002"
"a004"

输出曾是:

"Item a"
"Item x"

只有使用这个奇怪的循环命令,我才能设法搜索 ItemNumbers(并且该命令忽略第一行和最后一行)。

答案1

您的输入数据是一个 CSV 文件和一个无标头 CSV 文件。

首先向无标头 CSV 文件添加标头,以便稍后我们可以通过名称 来引用要加入的字段ItemNo。我们这样做是通过磨坊主( mlr),使用无标题方式读取数据--implicit-csv-header,然后使用label子命令将标签添加ItemNo到第一列。

$ mlr --csv --implicit-csv-header label ItemNo itemno.csv
ItemNo
a003
a001
a004

通过使用--implicit-csv-header,Miller 在内部将第一个字段标记为,而1不是从第一行选取标签。然后子命令label将其更改为ItemNo

输出中的数据未加引号这一事实并不重要,因为它不需要加引号(它不包含嵌入的分隔符或换行符等)。Miller 会自动引用需要加引号的字段。

然后我们可以在joinMiller 的操作中使用它:

$ mlr --csv --implicit-csv-header label ItemNo itemno.csv | mlr --csv join -f file.csv -j ItemNo
ItemNo,Name,Weight
a003,Item_4,1.0
a001,Item a,1.1
a004,Item b,1.1

ItemNo这在输入数据的字段file.csv和来自mlr管道中第一个命令的数据之间执行关系“内连接”操作。

cut然后我们可以对提取字段的操作进行字符串操作Name

$ mlr --csv --implicit-csv-header label ItemNo itemno.csv | mlr --csv join -f file.csv -j ItemNo then cut -f Name
Name
Item_4
Item a
Item b

添加--headerless-csv-output我们可以获得问题中的无标头 CSV 输出,并且--quote-all我们可以强制 Miller 引用所有输出字段,即使没有必要这样做:

$ mlr --csv --implicit-csv-header label ItemNo itemno.csv | mlr --csv --headerless-csv-output --quote-all join -f file.csv -j ItemNo then cut -f Name
"Item_4"
"Item a"
"Item b"

Miller 不关心输入文件是 DOS 还是 Unix 文本文件,它能够解析具有复杂字段的 CSV 文件。

答案2

使用任何 awk:

$ awk -F, '{sub(/\r$/,"")} NR==FNR{a[$1]; next} $1 in a{print $2}' itemno.csv file.csv
"Item a"
"Item_4"
"Item b"

自从您更新问题告诉我们您有 DOS 行结尾以来,我sub()在前面添加了这一点。

答案3

现在我知道我的问题是什么了。

项目编号.csv曾是:

"a003"\r
"a001"\r
"a004"

如果每行末尾没有 \r,该命令

grep -f itemno.csv file.csv | awk -F, '{print $2}'

工作得更好并且输出

"Item_4"
"Item a"
"Item b"
"a004"

如果每行末尾没有 \r,该命令

awk -F, 'NR==FNR{a[$1]; next} $1 in a{print $2}' itemno.csv file.csv

工作得更好并且输出

"Item_4"
"Item a"
"Item b"

如果每行末尾没有 \r,则该命令为循环命令

while read line; do
    grep "${line}" file.csv | awk -F "," '{print $2}';
done < itemno.csv 

给出这个输出

"Item_4"
"Item a"

因为该while read命令没有读取最后一行。

相关内容