尝试使用从 .csv 文件读取中设置的变量作为模式来 grep 第二个 .csv 文件

尝试使用从 .csv 文件读取中设置的变量作为模式来 grep 第二个 .csv 文件

我有两个 .csv 文件。第一个文件有一列单词。第二个文件有两列,第一列包含与第一个文件中的一个条目匹配的值。我想逐行读取第一个文件,并使用每一行对第二个文件进行 grep 查询。显示当前代码

  1. 读取行时
  2. grep $line ./filetwo.csv
  3. 完成 < fileone.csv

这段代码什么也没产生。如果我用一个不是通过读取文件分配的变量替换 $line ,它就可以完美工作。我多年来一直在研究这个问题,但从未找到一个看似简单的问题的答案。我不明白为什么通过读取 .csv 文件分配的变量不能提供与直接分配的变量相同的结果。我正在使用 zsh shell。

答案1

CSV 文件在 Microsoft 世界中更为常见,因此您可能会发现:

  • 它们以 UTF-16 编码,而不是区域设置的字符集,因此需要进行转换。
  • 或者它们以 UTF-8 编码但带有字节顺序标记。
  • 他们有 CRLF 行分隔符。
  • 它们的最后一行没有分隔(因此read会返回 false)。

您可以检查一下是否属于这种情况file yourfile.csv

然后你可以这样做:

dos2unix < fileone.csv |
  while IFS=, read -r first rest_if_any_ignored; do
    dos2unix < filetwo.csv | grep -Fe "$first"
  done

(请注意-Ffor 固定字符串搜索,而不是默认的进行正则表达式匹配( in regrep),但这效率相当低,因为它为每一行运行三个命令fileone.csv,并且每个命令每次都从头开始grep 处理内容。filetwo.csv

$first它还会在 中的任何位置查找字符串filetwo.csv,而不仅仅是第一列,并且不会执行精确匹配。例如,如果$firstis foo,则将报告foobar,otherother,foobar行。这也不处理 CSV 引用。因此,您最好使用具有正确 CSV 解析功能的语言。

如果这些文件是简单的 CSV,即没有引用也没有标题,那么这将是这里的工作join

preprocess() {
  dos2unix -O -- "$@" | sort -t, -k1b,1
}

join -t, <(preprocess < fileone.csv) <(preprocess < filetwo.csv)

对于真正的 CSV,带有标题和可能的引用(包括包含换行符的数据),您可以使用 CSV 解析器,mlr例如它的join动词

例如,如果第一列被称为fooinfileone.csvbarin filetwo.csv

mlr --csv join -j foo -r bar -f fileone.csv filetwo.csv

它可以处理 CRLF、无分隔行和带 BOM 的 UTF-8,但不能处理 UTF-16,您需要先使用 或 转换为 UTF- dos2unix8 iconv

mlr还可以执行简单的 CSV 和其他几种表格格式。详细信息请查看其手册。

相关内容