我有一个文件.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 会自动引用需要加引号的字段。
然后我们可以在join
Miller 的操作中使用它:
$ 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
命令没有读取最后一行。