Bash(或替代)使用另一个csv文件查找和替换csv文件中的许多模式

时间:2017-02-28 18:45:31

标签: string bash csv awk

我有一个非常大的csv文件太大而无法在excel中打开此操作。

我需要在csv的1.5mil中替换大约6000条记录的特定字符串,字符串本身采用逗号分隔格式,如下所示:

ABC,FOO.BAR,123456

任何一方的其他列都无关紧要。我只需要足够的数据来确保最终的数据字符串(数字)是唯一的。

我有另一个文件,其中包含要替换的字符串和替换字符串(如上所述):

"ABC,FOO.BAR,123456","ABC,FOO.BAR,654321"

所以在上面的情况下,123456正在被654321取代。一个简单(但令人发狂的慢)方法是在notepad ++中打开两个文档并找到第一个字符串然后用第二个字符串替换,但是有超过6000个记录这个不是很好。

我希望有人能就脚本解决方案提出建议吗? e.g:

$file1 = base.csv
$file2 = replace.csv

For each row in $file2 {
awk '{sub(/$file2($firstcolumn)/,$file2($Secondcolumn)' $file1 
}

虽然我不完全确定如何使awk适应这样的操作..

编辑:对不起,我应该更具体一点,我替换csv中的数据只有两列;两个原始字符串!

3 个答案:

答案 0 :(得分:3)

awk -F\" '
 NR==FNR { subst[$2]=$4; next }
 { 
   for (s in subst) {
     pos = index($0, s)
     if (pos) {
       $0 = substr($0, 1, pos-1) subst[s] substr($0, pos + length(s))
       break
     }
   }
   print
 }
' "$file2" "$file1"  # > "$file1.$$.tmp" && mv "$file1.$$.tmp" "$file1"

#之后的部分显示了如何用输出替换输入数据文件。

  • NR==FNR关联的块仅针对第一个输入文件执行,该文件具有搜索和替换字符串。

    • subst[$2]=$4构建一个关联数组(字典):键是搜索字符串,值是替换字符串。

    • 字段$2$4分别是搜索字符串和替换字符串,因为已指示Awk通过"({{1}将输入分成字段}});请注意,这假设您的字符串不包含转义的嵌入式 -F\"字符。

  • 然后剩余的块处理数据文件:

    • 对于每个输入行,它遍历搜索字符串并在当前行上查找匹配项:

      • 找到匹配项后,替换字符串将替换搜索字符串,匹配将停止。
    • "只打印(可能已修改)的行。

请注意,由于您需要 literal 字符串替换,因此明确避免使用基于 regex 的函数,例如print,以支持文字字符串处理函数{{ 1}}和sub()

顺便说一句:既然你说数据文件的两边都有列,那么考虑通过在index()的任意一侧放置substr()来使搜索/替换字符串更加健壮(这可以在{ {1}}脚本)。

答案 1 :(得分:2)

如果您的分隔符未在字段中使用,那么当然会更容易...

您可以分两步完成,从查找文件创建一个sed脚本,并将其用于替换主数据文件

例如,

(假设字段中没有转义引号,可能不会保留)

$ awk -F'","' '{print "s/" $1 "\"/\"" $2 "/"}' lookup_file > replace.sed
$ sed -f replace.sed data_file 

答案 2 :(得分:2)

我建议使用带有CSV解析库的语言,而不是尝试使用shell工具执行此操作。例如,Ruby:

require 'csv'
replacements = CSV.open('replace.csv','r').to_h
File.open('base.csv', 'r').each_line do |line|
  replacements.each do |old, new|
    line.gsub!(old) { new }
  end
  puts line
end

请注意Enumerable#to_h需要Ruby v2.1 +;用旧版Rubys代替:

replacements = Hash[*CSV.open('replace.csv','r').to_a.flatten]

您只需要CSV替换文件;这假设您可以将替换文件作为纯文本应用于另一个文件,这会加快速度并避免将旧/新字符串解析为字段本身。