【问题标题】:use awk to search for match and rename使用 awk 搜索匹配和重命名
【发布时间】:2014-06-09 04:13:20
【问题描述】:

我正在努力寻找解决方案,希望有人能提供帮助。我有两个文件... File1 包含一长串为某些示例序列(单列)编码的唯一字符串。 File2 包含许多记录和许多列,但这里的记录组织了具有匹配样本序列的唯一字符串。我希望 AWK 在 File2 中搜索 File1 中的每个唯一字符串,并将 File1 中的唯一字符串重命名为 File2 的 $1 中找到的字符串,该字符串与找到唯一字符串的记录相对应。

文件1

id1
id2
id3
id4
id5
id6
id7
id8
id9
id10

文件2

id1,id9,id33,id35,id36,id37,id76
id5,id7,id8,id20,id22,id23
id6,id11,id13,id14

期望的输出

id1
id2
id3
id4
id5
id6
id5
id5
id1
id10

我的实际 File1 在 $1 中有大约 17,000 条记录,而 File2 有大约 4,000 条记录,有 1-400 个字段。任何帮助表示赞赏!

【问题讨论】:

    标签: regex string bash awk match


    【解决方案1】:

    我不知道。赛德?

    sed 's/^\([^,]*\),\(.*\)/s;\\(\2\\);\1;/' File2 | sed 's/,/\\|/g' > temp.sed
    sed -f temp.sed File1 > Desired
    

    【讨论】:

    • 这对示例文件非常有用,但不适用于我正在使用的大文件。我根本不熟悉 sed(真的是编程新手),但我认为它不起作用,因为并非文件 2 的所有记录都有多个字段,所以有些记录没有s;\(|id#\);id#; 模式?这是我得到的错误sed: 1: temp.sed: unterminated substitute pattern
    • sed 只是进行普通的搜索和替换。可能您的某个字段有一个分号,我将其用作分隔符。
    【解决方案2】:

    试试这个:

    awk '
    NR==FNR {
      lines[$0]++;
      next
    }
    {
      for(line in lines) {
        num = split(line, flds, /,/);
        for(i=1; i<=num; i++) {
          if(flds[i] == $1) {
            print flds[1]; next
          }
        }
      }
      print $1; next
    }' file2 file1
    id1
    id2
    id3
    id4
    id5
    id6
    id5
    id5
    id1
    id10
    
    • 我们首先扫描 file2 并将 file2 中的整行存储在一个名为 lines 的数组中作为键
    • 一旦文件 2 完全存储,我们将移动到文件 1。
    • 对于lines 数组中的每一行,我们以, 作为分隔符分割行,并将行中的值存储在flds 数组中
    • 我们遍历我们的flds 数组。如果我们在数组中找到与 file1 中的 column1 匹配的值,我们将打印数组的第一个元素(即 file2 中的 column1)。
    • 如果我们在扫描所有行后没有找到匹配项,我们只需按原样打印 file1 中的 column1。

    【讨论】:

    • 这段代码非常适合我发布的示例,但是当我使用实际的大文件运行它时,它会不停地输出。它可能已经打印了所有的迭代,而不仅仅是 file1 的替换输出。不知道发生了什么,我不得不中断运行。
    • 注意文件传递的顺序。将 file2 放在 file1 之前。
    【解决方案3】:

    这是另一种 awk 方法。将以下内容放入可执行的 awk 文件中:

    #!/usr/bin/awk -f
    
    FNR==NR {f1[$0]=NR; out[NR]=$0; cnt=NR; next}
    
    {
    split($0, f2_line, ",")
    for( fld in f2_line ) {
        f1_line_num=f1[f2_line[fld]]
        if( f1_line_num!="" ) out[f1_line_num]=f2_line[1]
        }
    }
    
    END { for( j=1;j<=cnt;j++ ) print out[j] }
    

    如果你调用可执行的 awk 文件 awko,你会像 awko file1 file2 一样运行它。从问题中显示的输入中产生所需的输出。

    细分:

    • 制作两个 file1 数组,一个以唯一 ID (f1) 为键,另一个以行号 (out) 为键。
    • 将file2中的每一行解析成一个数组(f2_line)
    • 对于f2_line中的每个字段,检查f1中是否有行号并将其设置为f1_line_num
    • 如果f1_line_num不为空,则替换out中的对应条目。
    • END,按行号顺序打印out

    【讨论】:

    • 这非常有效!谢谢你的崩溃。从 file2 中创建一个用于递归搜索的数组是天才!
    • 很高兴它对你有用,但我想指出没有递归发生。 file2 正在按顺序检查,逐行和每行中的字段与由 file1 组成的关联数组进行比较。相比之下,@JS웃 的答案是将file2 放入一个数组并逐行检查file1,这意味着答案不需要像我这样用于保留file1out 数组输出顺序。我们的两个答案都来自split()file2,但使用不同的来源。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-27
    • 2015-07-07
    • 1970-01-01
    • 2014-12-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多